Java IO结构各种流详解

花了两天时间研究了一下Java IO的流,对于各种流,加深了一下理解

首先看我做的思维导图

文件流

public class FileIO {
    public static void main(String[] args) throws Exception {
        File file1 = new File(System.getProperty("user.dir") + "/c.txt"); // 找到第一个文件的File
        // 找到目标文件路径
        File file2 = new File(System.getProperty("user.dir") + "/d.txt");
        if (file1.exists()) {
            InputStream input = new FileInputStream(file1); // 输入流
            OutputStream output = new FileOutputStream(file2); // 输出流
            int temp = 0;
            while ((temp = input.read()) != -1) { // 表示还有内容可以继续读
                output.write(temp); // 写入数据
            }
            System.out.println("文件复制成功");
            input.close();
            output.close();
        } else {
            System.out.println("文件不存在");
        }
    }
}

对象流

当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

  把Java对象转换为字节序列的过程称为对象的序列化。

  把字节序列恢复为Java对象的过程称为对象的反序列化。

  对象的序列化主要有两种用途:

  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;

  2) 在网络上传送对象的字节序列。

java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。

  java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。、

  只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以采用默认的序列化方式 。

  对象序列化包括如下步骤:

  1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;

  2) 通过对象输出流的writeObject()方法写对象。

  对象反序列化的步骤如下:

  1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;

  2) 通过对象输入流的readObject()方法读取对象。

public class ObjectIO {

    public static void main(String[] args) throws IOException {
        ObjectInputStream ois=null;
        ObjectOutputStream oos=null;
        try {
              oos=new ObjectOutputStream(new FileOutputStream(System.getProperty("user.dir")+"/obj.txt"));
            Person p=new Person("汤高",20);
            oos.writeObject(p);

            ois=new ObjectInputStream(new FileInputStream(System.getProperty("user.dir")+"/obj.txt"));
            Person pp=(Person) ois.readObject();
            System.out.println("姓名  :"+pp.getName());
            System.out.println("年龄  :"+pp.getAge());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            oos.close();
            ois.close();

        }
    }
}

结果:

姓名 :汤高

年龄 :20

如果我只要对部分属性进行序列化,可以使对象,实现Externalizable接口,并重写两个方法

public class Person2 implements Externalizable{
    private String name;
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Person2(String name, Integer age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Person2() {
        super();
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((age == null) ? 0 : age.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person2 other = (Person2) obj;
        if (age == null) {
            if (other.age != null)
                return false;
        } else if (!age.equals(other.age))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        this.name=(String) in.readObject();

    }
    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(this.name);

    }

}
public static void main(String[] args) throws IOException {
        ObjectInputStream ois=null;
        ObjectOutputStream oos=null;
        try {
              oos=new ObjectOutputStream(new FileOutputStream(System.getProperty("user.dir")+"/obj.txt"));
            Person2 p=new Person2("汤高",20);
            oos.writeObject(p);
            ois=new ObjectInputStream(new FileInputStream(System.getProperty("user.dir")+"/obj.txt"));
            Person2 pp=(Person2) ois.readObject();
            System.out.println("姓名  :"+pp.getName());
            System.out.println("年龄  :"+pp.getAge());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            oos.close();
            ois.close();

        }
    }
}

结果

姓名 :汤高

年龄 :null

还有一种办法,用到transient关键字

public class Person3 implements Serializable{
    /**
     *
     */
    private static final long serialVersionUID = 2474657820412854900L;
    private String name;
    private transient Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Person3(String name, Integer age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Person3() {
        super();
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((age == null) ? 0 : age.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person3 other = (Person3) obj;
        if (age == null) {
            if (other.age != null)
                return false;
        } else if (!age.equals(other.age))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

}
public class ObjectIO3 {

    public static void main(String[] args) throws IOException {
        ObjectInputStream ois=null;
        ObjectOutputStream oos=null;
        try {
              oos=new ObjectOutputStream(new FileOutputStream(System.getProperty("user.dir")+"/obj.txt"));
            Person3 p=new Person3("汤高",20);
            oos.writeObject(p);

            ois=new ObjectInputStream(new FileInputStream(System.getProperty("user.dir")+"/obj.txt"));
            Person3 pp=(Person3) ois.readObject();
            System.out.println("姓名  :"+pp.getName());
            System.out.println("年龄  :"+pp.getAge());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            oos.close();
            ois.close();

        }
    }
}

结果同上

合并流

将多个文件合成一个文件

有些情况下,当我们需要从多个输入流中向程序读入数据。此时,可以使用合并流,将多个输入流合并成一个SequenceInputStream流对象

SequenceInputStream会将与之相连接的流集组合成一个输入流并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。 合并流的作用是将多个源合并合一个源。

SequenceInputStream

public SequenceInputStream(Enumeration

public class SequenceInput {

    public static void main(String[] args) {

        try {
            InputStream fis1=new  FileInputStream(System.getProperty("user.dir")+"/a.txt");
            InputStream fis2=new  FileInputStream(System.getProperty("user.dir")+"/b.txt");
            OutputStream os=new FileOutputStream(System.getProperty("user.dir")+"/ab.txt");
            SequenceInputStream sis=new SequenceInputStream(fis1,fis2);

            int temp=0;
            while((temp=sis.read())!=-1){
                os.write(temp);
            }
            sis.close();
            fis1.close();
            fis2.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

a.txt:hello tanggao

b.txt:hello zhousiyuan

结果:ab.txt hello tanggao hello zhousiyuan

public class SequnceInput2 {
    public static void main(String[] args)throws IOException
    {

        Vector<FileInputStream> v = new Vector<FileInputStream>();

        v.add(new  FileInputStream(System.getProperty("user.dir")+"/a.txt"));
        v.add(new  FileInputStream(System.getProperty("user.dir")+"/b.txt"));

        Enumeration<FileInputStream> en = v.elements();

        SequenceInputStream sis = new SequenceInputStream(en);

        FileOutputStream fos = new FileOutputStream(System.getProperty("user.dir")+"/c.txt");
        byte[] buf = new byte[1024];
        int len = 0;
        while((len=sis.read(buf,0,buf.length))!=-1)
        {
            fos.write(buf,0,len);
        }
        fos.close();
        sis.close();

    }
}

管道流

管道流可以实现两个线程之间,二进制数据的传输。管道流就像一条管道,一端输入数据,别一端则输出数据。通常要分别用两个不同的线程来控制它们。如果要进行管道输出,则必须把输出流连在输入流上。

public class Send implements Runnable {

    public PipedOutputStream getPos() {
        return pos;
    }

    private PipedOutputStream pos = null;
    public Send() {
        // 实例化输出流
        pos = new PipedOutputStream();
    }

    @Override
    public void run() {
        String str = "你好,汤高";
        try {
            pos.write(str.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                pos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Receive implements Runnable {
    private PipedInputStream pis=null;

    public Receive() {
        pis = new PipedInputStream();
    }

    public PipedInputStream getPis() {
        return pis;
    }

    @Override
    public void run() {
        byte [] b=new byte[1024];
        int len=0;
        try {
            len=this.pis.read(b);
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                this.pis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("接收的内容为: "+new String(b,0,len));
    }
}
public class PipeIO {

    public static void main(String[] args) {
        Send s=new Send();
        Receive  r=new Receive();

        try {
            s.getPos().connect(r.getPis());
        } catch (IOException e) {
            e.printStackTrace();
        }
        new Thread(s).start();
        new Thread(r).start();

    }
}

结果:

接收的内容为: 你好,汤高

内存操作流

在之前讲解FileInputStream 和 FileOutputStream 的时候所有的操作的目标是文件,那么如果现在假设有一些临时的信息要求通过IO操作的话,那么如果将这些临时的信息保存在文件之中则肯定很不合理,因为操作的最后还要把文件再删除掉,所以此时的IO中就提供了一个内存的操作流,通过内存操作流输入和输出的目标是内存。

在内存操作流中所有的输入和输出都是以内存为操作的源头

ByteArrayOutputStream 是用于从内存向程序输出的

ByteArrayInputStream 是用于从程序向内存写入的

ByteArrayInputStream 的构造方法: public ByteArrayInputStream(byte[] buf)

表示把内容向内存之中写入

ByteArrayOutputStream来讲,其基本的作用就是与OutputStream一样,一个个的读取数据。

public class ByteArrayIO {

    public static void main(String[] args) throws IOException {

        String str="汤高,你好";
        ByteArrayInputStream bai=new ByteArrayInputStream(str.getBytes());

        ByteArrayOutputStream  bao=new ByteArrayOutputStream();

        int len=0;
        while((len=bai.read())!=-1){
            char c=(char) len;
            bao.write(Character.toLowerCase(c));
        }
        System.out.println("输出"+bao.toString());
        bai.close();
        bao.close();
    }

}

结果:

输出 hello ,tanggao

字符串变成小写了,全部操作都是在内存中进行的

过滤流–打印流

打印流分两种:PrintStream(字节)、PrintWriter(字符)

打印流是输出信息最方便的类,可以打印任何数据类型

public class PrintIO1 {
    public static void main(String[] args) throws FileNotFoundException {
        PrintStream ps=new PrintStream(new FileOutputStream(System.getProperty("user.dir")+"/print.txt"));
        ps.print("hello     ");

        ps.println("汤高");

        ps.print("1+1="+2);

        ps.print("1+1=3  对吗     ?"+false);
ps.close();

    }

}

结果 print.txt内容:

hello 汤高

1+1=21+1=3 对吗 ?false

使用打印流进行格式化

public class PrintIO2 {
    public static void main(String[] args) throws FileNotFoundException {
        PrintStream ps=new PrintStream(new FileOutputStream(System.getProperty("user.dir")+"/print.txt"));
//      PrintWriter ps=new PrintWriter(new //FileOutputStream(System.getProperty("user.dir")+"/print.//txt"));

        ps.print("hello     ");

        ps.println("汤高");

        ps.print("1+1="+2);

        ps.print("1+1=3  对吗     ?"+false);
        ps.close();

    }

}

结果:

姓名:汤高 年龄:20 分数:99.10 性别:M

过滤流–缓存流

java IO通过缓冲流来提高读写效率,普通的字节、字符流都是一个字节一个字符这样读取的,而缓冲流则是将数据先缓冲起来,然后一起写入或者读取出来。经常使用的是readLine()方法,表示一次读取一行数据。

public class BufferedIO {
    public static void main(String[] args) throws IOException {
         // 指定要读取文件的缓冲输入字节流
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(System.getProperty("user.dir")+"/tg.jpg"));
        File file = new File(System.getProperty("user.dir")+"/tg2.jpg");
        if (file != null) {
            file.createNewFile();
        }
        // 指定要写入文件的缓冲输出字节流
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
        byte[] bb = new byte[1024];// 用来存储每次读取到的字节数组
        int n;// 每次读取到的字节数组的长度
        while ((n = in.read(bb,0,bb.length)) != -1) {
            out.write(bb, 0, n);// 写入到输出流
        }
        out.close();// 关闭流
        in.close();
    }
}

完成了图片的复制

字节流和字符流的区别

字节流在操作时不会用到缓冲区(内存),是文件本身直接操作的,而字符流用到了缓冲区,通过缓冲区再操作文件

在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成。

程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。

字节流与字符流

在java.io包中操作文件内容的主要有两大类:字节流、字符流,两类都分为输入和输出操作。在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,在字符流中输出主要是使用Writer类完成,输入流主要使用Reader类完成。(这四个都是抽象类)

java中提供了专用于输入输出功能的包Java.io,其中包括:

InputStream,OutputStream,Reader,Writer

InputStream 和OutputStream,两个是为字节流设计的,主要用来处理字节或二进制对象,

Reader和 Writer.两个是为字符流(一个字符占两个字节)设计的,主要用来处理字符或字符串.

字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好点

所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列

字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串; 2. 字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以

字节流是最基本的,所有的InputStrem和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的 但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化 这两个之间通过 InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联 在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而造成的

public class BufferReaderIO {
    public static void main(String[] args) {
        write();
        read();
    }

    public static void write() {
        FileWriter fw = null;
        BufferedWriter bw = null;
        // 缓冲字符输出流去写入数据
        try {
            fw = new FileWriter("demo.txt");
            bw = new BufferedWriter(fw);
            bw.write("Hello");
            bw.newLine();// 换行符标记
            bw.write("Java");
            bw.newLine();
            bw.flush();// 把缓冲区里的内容刷新到目的地
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void read() {
        // 读出
        FileReader fr = null;
        BufferedReader br = null;

        try {
            fr = new FileReader("demo.txt");// 节点流
            br = new BufferedReader(fr, 255);// 255为缓冲区的大小
            String str = null;// 用于存储每一次读取出来的数据
            while ((str = br.readLine()) != null) {
                System.out.println(str);
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

转换流

java提供将字节流转化为字符流读写方式的OutputStreamWriter和InputStreamReader

public class zhunhuanIO {
    public static void main(String args[]) throws Exception{    //所有异常抛出
        //写入数据
        File file=new File("test.txt");
        Writer writer=null;     //字符输出流
        writer=new OutputStreamWriter(new FileOutputStream(file));  //字节流变为字符流
        String str="hello world!!!!";
        writer.write(str);  //使用字符流输出
        writer.close();  

        //读取文件
        File f = new File("test.txt") ;
        Reader reader = null ;
        reader = new InputStreamReader(new FileInputStream(f)) ;    // 将字节流变为字符流
        char c[] = new char[1024] ;
        int len = reader.read(c) ;  // 读取
        reader.close() ;    // 关闭
        System.out.println(new String(c,0,len)) ;
    }
}

回退流

回退:给了用户第二次读的机会。

使用InputStream 要使用read() 方法不断读取,是采用顺序的读取方式。回退操作同样分为字节流和字符流,本例还是以字节流为准。

public class PushInputStreamDemo {
    public static void main(String args[]) throws Exception {   // 所有异常抛出
        String str = "www.mldnjava.cn" ;        // 定义字符串
        PushbackInputStream push = null ;       // 定义回退流对象
        ByteArrayInputStream bai = null ;       // 定义内存输入流
        bai = new ByteArrayInputStream(str.getBytes()) ;    // 实例化内存输入流
        push = new PushbackInputStream(bai) ;   // 从内存中读取数据
        System.out.print("读取之后的数据为:") ;
        int temp = 0 ;
        while((temp=push.read())!=-1){  // 读取内容
            if(temp==‘.‘){  // 判断是否读取到了“.”
                push.unread(temp) ; // 放回到缓冲区之中
                temp = push.read() ;    // 再读一遍,不写的话就断了
                System.out.print("(退回"+(char)temp+")") ;
            }else{
                System.out.print((char)temp) ;  // 输出内容
            }
        }
    }
}

结果:

读取之后的数据为:www(退回.)mldnjava(退回.)cn

压缩流

压缩一个文件

public class ZipOutputStreamDemo01 {
    public static void main(String args[]) throws Exception { // 所有异常抛出
        File file = new File("a.txt"); // 定义要压缩的文件
        File zipFile = new File("a.zip"); // 定义压缩文件名称
        InputStream input = new FileInputStream(file); // 定义文件的输入流
        ZipOutputStream zipOut = null; // 声明压缩流对象
        zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
        zipOut.putNextEntry(new ZipEntry(file.getName())); // 设置ZipEntry对象
        zipOut.setComment("www.mldnjava.cn"); // 设置注释
        int temp = 0;
        while ((temp = input.read()) != -1) { // 读取内容
            zipOut.write(temp); // 压缩输出
        }
        input.close(); // 关闭输入流
        zipOut.close(); // 关闭输出流
    }
}

压缩一个文件夹

public class ZipOutputStreamDemo02{
    public static void main(String args[]) throws Exception{    // 所有异常抛出
        File file = new File("tg") ;    // 定义要压缩的文件夹
        File zipFile = new File("tg.zip") ; // 定义压缩文件名称
        InputStream input = null ;  // 定义文件输入流
        ZipOutputStream zipOut = null ; // 声明压缩流对象
        zipOut = new ZipOutputStream(new FileOutputStream(zipFile)) ;
        zipOut.setComment("www.tanggao.cn") ;   // 设置注释
        int temp = 0 ;
        if(file.isDirectory()){ // 判断是否是文件夹
            File lists[] = file.listFiles() ;   // 列出全部文件
            for(int i=0;i<lists.length;i++){
                input = new FileInputStream(lists[i]) ; // 定义文件的输入流
                zipOut.putNextEntry(new ZipEntry(file.getName()
                    +File.separator+lists[i].getName())) ;  // 设置ZipEntry对象
                while((temp=input.read())!=-1){ // 读取内容
                    zipOut.write(temp) ;    // 压缩输出
                }
                input.close() ; // 关闭输入流
            }
        }
        zipOut.close() ;    // 关闭输出流
    }
}

ZipFile

是一个专门表示压缩文件的类。

ipFile 在实例化的时候必须接收File 类的实例。此File 类的实例是指向一个压缩 *.zip 文件。

ZipInputStream 结合 ZipFile 就可以完成解压缩文件夹的功能

ZipFile 对象,可以找到每一个ZipEntry 的输入流。但是ZipInputStream 并不能得到每一个输入流,所以需要使用ZipFile,但是ZipInputStream 在取得每一个ZipEntry 的时候,不需要每一个ZipEntry 的名称。

public class ZipInputStreamDemo{
    public static void main(String args[]) throws Exception{    // 所有异常抛出
        File file = new File("tg.zip") ;    // 定义压缩文件名称
        File outFile = null ;   // 输出文件的时候要有文件夹的操作
        ZipFile zipFile = new ZipFile(file) ;   // 实例化ZipFile对象
        ZipInputStream zipInput = null ;    // 定义压缩输入流
        OutputStream out = null ;   // 定义输出流,用于输出每一个实体内容
        InputStream input = null ;  // 定义输入流,读取每一个ZipEntry
        ZipEntry entry = null ; // 每一个压缩实体
        zipInput = new ZipInputStream(new FileInputStream(file)) ;  // 实例化ZIpInputStream
        while((entry = zipInput.getNextEntry())!=null){ // 得到一个压缩实体
            System.out.println("解压缩" + entry.getName() + "文件。") ;
            outFile = new File( entry.getName()) ;  // 定义输出的文件路径
            if(!outFile.getParentFile().exists()){  // 如果输出文件夹不存在
                outFile.getParentFile().mkdir() ;   // 创建文件夹
            }
            if(!outFile.exists()){  // 判断输出文件是否存在
                outFile.createNewFile() ;   // 创建文件
            }
            input = zipFile.getInputStream(entry) ; // 得到每一个实体的输入流
            out = new FileOutputStream(outFile) ;   // 实例化文件输出流
            int temp = 0 ;
            while((temp=input.read())!=-1){
                out.write(temp) ;
            }
            input.close() ;     // 关闭输入流
            out.close() ;   // 关闭输出流
        }
        input.close() ;
    }
}

1、压缩文件中的每一个压缩实体都使用ZipEntry 保存,一个压缩文件中可能包含一个或多个的ZipEntry 对象。

2、在JAVA中可以进行zip、jar、gz、三种格式的压缩支持,操作流程基本上是一样的

3、ZipOutputStream 可以进行压缩输出,但是输出的位置不一定是文件。

4、ZipFile 表示每一个压缩文件,可以得到每一个压缩实体的输入流,得到实体要知道文件名称,不方便

5、ZipInputStream 可以得到每一个实体,但是却无法得到每一个实体的输入流

所以两则结合用完成解压功能

数据操作流:

DataOutputStream 和 DataInputStream

数据输出流会按照一定的格式将数据输出,再通过数据输入流按照一定的格式将数据读入,这样可以方便对数据进行处理

数据写入格式

每一行的数据,通过 “ \n “ 完结,每行中的各个数据之间通过 ” \t “ 完结

public class DataOutputStreamDemo{
    public static void main(String args[]) throws Exception{    // 所有异常抛出
        DataOutputStream dos = null ;           // 声明数据输出流对象
        File f = new File("order.txt") ; // 文件的保存路径
        dos = new DataOutputStream(new FileOutputStream(f)) ;   // 实例化数据输出流对象
        String names[] = {"衬衣","手套","围巾"} ; // 商品名称
        float prices[] = {98.3f,30.3f,50.5f} ;      // 商品价格
        int nums[] = {3,2,1} ;  // 商品数量
        for(int i=0;i<names.length;i++){    // 循环输出
            dos.writeChars(names[i]) ;  // 写入字符串
            dos.writeChar(‘\t‘) ;   // 写入分隔符
            dos.writeFloat(prices[i]) ; // 写入价格
            dos.writeChar(‘\t‘) ;   // 写入分隔符
            dos.writeInt(nums[i]) ; // 写入数量
            dos.writeChar(‘\n‘) ;   // 换行
        }
        dos.close() ;   // 关闭输出流
    }
};

使用DataOutputStream 写入的数据要使用 DataInputStream 读取进来。

public class DataInputStreamDemo{
    public static void main(String args[]) throws Exception{    // 所有异常抛出
        DataInputStream dis = null ;        // 声明数据输入流对象
        File f = new File("order.txt") ; // 文件的保存路径
        dis = new DataInputStream(new FileInputStream(f)) ; // 实例化数据输入流对象
        String name = null ;    // 接收名称
        float price = 0.0f ;    // 接收价格
        int num = 0 ;   // 接收数量
        char temp[] = null ;    // 接收商品名称
        int len = 0 ;   // 保存读取数据的个数
        char c = 0 ;    // ‘\u0000‘
        try{
            while(true){
                temp = new char[200] ;  // 开辟空间
                len = 0 ;
                while((c=dis.readChar())!=‘\t‘){    // 接收内容
                    temp[len] = c ;
                    len ++ ;    // 读取长度加1
                }
                name = new String(temp,0,len) ; // 将字符数组变为String
                price = dis.readFloat() ;   // 读取价格
                dis.readChar() ;    // 读取\t
                num = dis.readInt() ;   // 读取int
                dis.readChar() ;    // 读取\n
                System.out.printf("名称:%s;价格:%5.2f;数量:%d\n",name,price,num) ;
            }
        }catch(Exception e){}
        dis.close() ;
    }
}

其他流

Java IO _System 类对IO的支持

System.out

public class SystemDemo01{
    public static void main(String args[]){
        OutputStream out = System.out ;     // 此时的输出流是向屏幕上输出
        try{
            out.write("hello world!!!".getBytes()) ;    // 向屏幕上输出
        }catch(IOException e){
            e.printStackTrace() ;   // 打印异常
        }
        try{
            out.close() ;   // 关闭输出流
        }catch(IOException e){
            e.printStackTrace() ;
        }
    }
}

System.err

public class SystemDemo02{
    public static void main(String args[]){
        String str = "hello" ;      // 声明一个非数字的字符串
        try{
            System.out.println(Integer.parseInt(str)) ; // 转型
        }catch(Exception e){
            System.err.println(e) ;
        }
    }
};  

System.in

public class SystemDemo04{
    public static void main(String args[]) throws Exception {   // 所有异常抛出
        InputStream input = System.in ; // 从键盘接收数据
        byte b[] = new byte[5] ;    // 开辟空间,接收数据
        System.out.print("请输入内容:") ;    // 提示信息
        int len = input.read(b) ;   // 接收数据
        System.out.println("输入的内容为:" + new String(b,0,len)) ;
        input.close() ; // 关闭输入流
    }
}; 

以上大部分都是对字节流做案例,字符流就不做演示了,直接把字节流换为字符流即可

码字不易,转载请指明出处

时间: 2024-10-06 21:26:13

Java IO结构各种流详解的相关文章

java知识点分享,IO流详解!

Java知识IO流详解有人觉得IO知识不太重要,其实不然,IO的使用范围很广,最能体现IO价值的就是网络上的数据传递,尤其是进入互联网时代后,各种常见的分布式架构,都少不了IO的体现.并且很多大厂的面试题中都会体现出对IO的重视,包括衍生出来的NIO.序列化等等.因此学好IO,变成了一件很重要的事情.IO基本概念IO可以简单的理解成INPUT和OUT,代表输入输出的意思.输入就是读,输出就是写.IO可以读写硬盘.光盘.内存.键盘.网络等资源上的数据.流IO中的流就相当于现实生活中的水流一样,一打

Java IO流详解

初学java,一直搞不懂java里面的io关系,在网上找了很多大多都是给个结构图草草描述也看的不是很懂.而且没有结合到java7 的最新技术,所以自己来整理一下,有错的话请指正,也希望大家提出宝贵意见. 首先看个图:(如果你也是初学者,我相信你看了真个人都不好了,想想java设计者真是煞费苦心啊!) 这是java io 比较基本的一些处理流,除此之外我们还会提到一些比较深入的基于io的处理类,比如console类,SteamTokenzier,Externalizable接口,Serializa

基于JavaSE阶段的IO流详解

1.IO流基本概述 在Java语言中定义了许多针对不同的传输方式,最基本的就是输入输出流(俗称IO流),IO流是属于java.io包下的内容,在JavaSE阶段主要学下图所示的: 其中从图中可知,所有输入流类都是抽象类,是InputStream或者抽象类Reader的子类:而所有输出流都是抽象类,是OutputStream或者Writer的子类.输入输出流的定义是根据流向所决定的,我们可以是本地为一个实体物质,从外界往本地输入,按照本地的状态就是读取,反之,从本地向外写入就是输出.IO流是最基本

Java网络编程和NIO详解3:IO模型与Java网络编程模型

Java网络编程和NIO详解3:IO模型与Java网络编程模型 基本概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限.为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间.针对linux操作系统而言,将最高的1G字节(从虚拟地址

Java网络编程和NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型

Java网络编程与NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型 知识点 nio 下 I/O 阻塞与非阻塞实现 SocketChannel 介绍 I/O 多路复用的原理 事件选择器与 SocketChannel 的关系 事件监听类型 字节缓冲 ByteBuffer 数据结构 场景 接着上一篇中的站点访问问题,如果我们需要并发访问10个不同的网站,我们该如何处理? 在上一篇中,我们使用了java.net.socket类来实现了这样的需求,以一线程处理一连接的方式,并配以线程池的控制

Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO

Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO https://blog.csdn.net/column/details/21963.html 部分代码会放在我的的Github:https://github.com/h2p

Java核心知识点-字节流和字符流详解

字节流与和字符流的使用非常相似,两者除了操作代码上的不同之外,是否还有其他的不同呢? 区别:实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件,如图12-6所示. 下面以两个写文件的操作为主进行比较,但是在操作时字节流和字符流的操作完成之后都不关闭输出流. 范例:使用字节流不关闭执行 Java代码   package org.lxh.demo12.byteiodemo; import java.io.File; import 

Java语言Socket接口用法详解

Socket接口用法详解   在Java中,基于TCP协议实现网络通信的类有两个,在客户端的Socket类和在服务器端的ServerSocket类,ServerSocket类的功能是建立一个Server,并通过accept()方法随时监听客户端的连接请求. 扩展: ServerSocket中常用的构造函数及方法 构造函数:ServerSocket(int port) 这是一个构造方法,用于在当前的服务器默认的IP地址上监听一个指定的端口,即在指定的IP和端口创建一个ServerSocket对象

Java学习之道:详解Java解析XML的四种方法

XML现在已经成为一种通用的数据交换格式,它的平台无关性,语言无关性,系统无关性,给数据集成与交互带来了极大的方便.对于XML本身的语法知识与技术细节,需要阅读相关的技术文献,这里面包括的内容有DOM(Document Object Model),DTD(Document Type Definition),SAX(Simple API for XML),XSD(Xml Schema Definition),XSLT(Extensible Stylesheet Language Transform