IO流学习总结

一 分类

字节流和字符流:

  • 字节流:以字节为单位,每次次读入或读出是8位数据。可以读任何类型数据。
  • 字符流:以字符为单位,每次次读入或读出是16位数据。其只能读取字符类型数据。

输出流和输入流:

  • 输出流:从内存读出到文件。只能进行写操作。
  • 输入流:从文件读入到内存。只能进行读操作。

      注意: 这里的出和入,都是相对于系统内存而言的。

节点流和处理流:

  • 节点流:直接与数据源相连,读入或读出。
  • 处理流:与节点流一块使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。

为什么要有处理流?直接使用节点流,读写不方便,为了更快的读写文件,才有了处理流

1.1 按操作方式分类结构图

在这里插入图片描述

1.2 分类说明

1) 输入字节流InputStream
  • ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。
  • PipedInputStream 是从与其它线程共用的管道中读取数据。PipedInputStream的一个实例要和PipedOutputStream的一个实例共同使用,共同完成管道的读取写入操作。主要用于线程操作。
  • DataInputStream: 将基础数据类型读取出来
  • ObjectInputStream 和所有 FilterInputStream 的子类都是装饰流(装饰器模式的主角)。
2)字节流OutputStream
  • ByteArrayOutputStream、FileOutputStream: 是两种基本的介质流,它们分别向- Byte 数组、和本地文件中写入数据。
  • PipedOutputStream 是向与其它线程共用的管道中写入数据。
  • DataOutputStream 将基础数据类型写入到文件中
  • ObjectOutputStream 和所有 FilterOutputStream 的子类都是装饰流。

节流的输入和输出类结构图:
在这里插入图片描述

3)字符输入流Reader
  • FileReader、CharReader、StringReader 是三种基本的介质流,它们分在本地文件、Char 数组、String中读取数据。
  • PipedReader:是从与其它线程共用的管道中读取数据
  • BufferedReader :加缓冲功能,避免频繁读写硬盘
  • InputStreamReader: 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。
4)字符输出流Writer
  • StringWriter:向String 中写入数据。
  • CharArrayWriter:实现一个可用作字符输入流的字符缓冲区
  • PipedWriter:是向与其它线程共用的管道中写入数据
  • BufferedWriter : 增加缓冲功能,避免频繁读写硬盘。
  • PrintWriter 和PrintStream 将对象的格式表示打印到文本输出流。 极其类似,功能和使用也非常相似
  • OutputStreamWriter: 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream 极其类似。

字符流的输入和输出类结构图:
在这里插入图片描述

1.3 按操作对象分类结构图

在这里插入图片描述

1.4分类说明

1)对文件进行操作(节点流)
  • FileInputStream(字节输入流)
  • FileOutputStream(字节输出流)
  • FileReader(字符输入流)
  • FileWriter(字符输出流)
2)对管道进行操作(节点流)
  • PipedInputStream(字节输入流)
  • PipedOutStream(字节输出流)
  • PipedReader(字符输入流)
  • PipedWriter(字符输出流)
    PipedInputStream的一个实例要和PipedOutputStream的一个实例共同使用,共同完成管道的读取写入操作。主要用于线程操作。
3)字节/字符数组流(节点流)
  • ByteArrayInputStream
  • ByteArrayOutputStream
  • CharArrayReader
  • CharArrayWriter
    除了上述三种是节点流,其他都是处理流,需要跟节点流配合使用。
4)Buffered缓冲流(处理流)

带缓冲区的处理流,缓冲区的作用的主要目的是:避免每次和硬盘打交道,提高数据访问的效率。

  • BufferedInputStream
  • BufferedOutputStream
  • BufferedReader
  • BufferedWriter
5)转化流(处理流)
  • InputStreamReader:把字节转化成字符
  • OutputStreamWriter:把字节转化成字符
6)基本类型数据流(处理流)

用于操作基本数据类型值。

因为平时若是我们输出一个8个字节的long类型或4个字节的float类型,那怎么办呢?可以一个字节一个字节输出,也可以把转换成字符串输出,但是这样转换费时间,若是直接输出该多好啊,因此这个数据流就解决了我们输出数据类型的困难。数据流可以直接输出float类型或long类型,提高了数据读写的效率。

  • DataInputStream
  • DataOutputStream
7)打印流(处理流)

一般是打印到控制台,可以进行控制打印的地方。

  • PrintStream
  • PrintWriter
8)对象流(处理流)

把封装的对象直接输出,而不是一个个在转换成字符串再输出。

  • ObjectInputStream,对象反序列化
  • ObjectOutputStream,对象序列化
9)合并流(处理流)
  • SequenceInputStream:可以认为是一个工具类,将两个或者多个输入流当成一个输入流依次读取

1.5 java输入/输出流体系中常用的流的分类表

分类字节输入流字节输出流字符输入流字符输出流
抽象基类InputStreamOutputStreamReaderWriter
访问文件FileInputStreamFileOutputStreamFileReaderFileWriter
访问数组ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter
访问管道PipedInputStreamPipedOutputStreamPipedReaderPipedWriter
访问字符串StringReaderStringWriter
缓冲流BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter
转换流InputStreamReaderOutputStreamWriter
对象流ObjectInputStreamObjectOutputStream
打印流PrintStreamPrintWriter
推回输入流PushbackInputStreamPushbackReader
特殊流DataInputStreamDataOutputStream
注:表中粗体字所标出的类代表节点流,必须直接与指定的物理节点关联:斜体字标出的类代表抽象基类,无法直接创建实例。

二 常用的io流的用法

2.1 Io体系的基类

InputStream/Reader,OutputStream/Writer

InputStream和Reader是所有输入流的抽象基类,本身并不能创建实例来执行输入,但它们将成为所有输入流的模板,所以它们的方法是所有输入流都可使用的方法。

在InputStream里面包含如下3个方法。

  • int read(); 从输入流中读取单个字节,返回所读取的字节数据(字节数据可直接转换为int类型)。
  • int read(byte[] b)从输入流中最多读取b.length个字节的数据,并将其存储在字节数组b中,返回实际读取的字节数。
  • int read(byte[] b,int off,int len); 从输入流中最多读取len个字节的数据,并将其存储在数组b中,放入数组b中时,并不是从数组起点开始,而是从off位置开始,返回实际读取的字节数。

在Reader中包含如下3个方法。

  • int read(); 从输入流中读取单个字符,返回所读取的字符数据(字节数据可直接转换为int类型)。
  • int read(char[] b)从输入流中最多读取b.length个字符的数据,并将其存储在字节数组b中,返回实际读取的字符数。
  • int read(char[] b,int off,int len); 从输入流中最多读取len个字符的数据,并将其存储在数组b中,放入数组b中时,并不是从数组起点开始,而是从off位置开始,返回实际读取的字符数。

输入流模型图
在这里插入图片描述
InputStream和Reader提供的一些移动指针的方法:

  • void mark(int readAheadLimit); 在记录指针当前位置记录一个标记(mark)。
  • boolean markSupported(); 判断此输入流是否支持mark()操作,即是否支持记录标记。
  • void reset(); 将此流的记录指针重新定位到上一次记录标记(mark)的位置。
  • long skip(long n); 记录指针向前移动n个字节/字符。

OutputStream和Writer:

OutputStream和Writer的用法也非常相似,它们采用如图15.6所示的模型来执行输入,两个流都提供了如下三个方法:

  • void write(int c); 将指定的字节/字符输出到输出流中,其中c即可以代表字节,也可以代表字符。
  • void write(byte[]/char[] buf); 将字节数组/字符数组中的数据输出到指定输出流中。
  • void write(byte[]/char[] buf, int off,int len ); 将字节数组/字符数组中从off位置开始,长度为len的字节/字符输出到输出流中。

因为字符流直接以字符作为操作单位,所以Writer可以用字符串来代替字符数组,即以String对象作为参数。Writer里面还包含如下两个方法。

  • void write(String str); 将str字符串里包含的字符输出到指定输出流中。
  • void write (String str, int off, int len); 将str字符串里面从off位置开始,长度为len的字符输出到指定输出流中。

2.2 Io体系的基类文件流的使用

FileInputStream/FileReader ,FileOutputStream/FileWriter

前面说过InputStream和Reader都是抽象类,本身不能创建实例,但它们分别有一个用于读取文件的输入流:FileInputStream和FileReader,它们都是节点流——会直接和指定文件关联。

2.2.1FileInputStream和FileReader示例

使用FileInputStream读取文件:

public class MyClass {
  public  static void main(String[] args)throws IOException{
      FileInputStream fis=null;
      try {
          //创建字节输入流
          fis=new FileInputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\Test.txt");
          //创建一个长度为1024的竹筒
          byte[] b=new byte[1024];
          //用于保存的实际字节数
          int hasRead=0;
          //使用循环来重复取水的过程
          while((hasRead=fis.read(b))>0){
              //取出竹筒中的水滴(字节),将字节数组转换成字符串进行输出
            System.out.print(new String(b,0,hasRead));
          }
      }catch (IOException e){
        e.printStackTrace();
      }finally {
          fis.close();
      }
  }
}

使用FileReader读取文件:

public class FileReaderTest {
    public  static void main(String[] args)throws IOException{
        FileReader fis=null;
        try {
            //创建字符输入流
            fis=new FileReader("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\Test.txt");
            //创建一个长度为1024的竹筒
            char[] b=new char[1024];
            //用于保存的实际字节数
            int hasRead=0;
            //使用循环来重复取水的过程
            while((hasRead=fis.read(b))>0){
                //取出竹筒中的水滴(字节),将字节数组转换成字符串进行输出
                System.out.print(new String(b,0,hasRead));
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            fis.close();
        }
    }
}

结论:

可以看出使用FileInputStream和FileReader进行文件的读写并没有什么区别,只是操作单元不同而已。
2.2.2 FileOutputStream/FileWriter示例

FileOutputStream/FileWriter是Io中的文件输出流。

FileOutputStream的示例:

public class FileOutputStreamTest {
    public  static void main(String[] args)throws IOException {
        FileInputStream fis=null;
        FileOutputStream fos=null;
        try {
            //创建字节输入流
            fis=new FileInputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\Test.txt");
            //创建字节输出流
            fos=new FileOutputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\newTest.txt");

            byte[] b=new byte[1024];
            int hasRead=0;

            //循环从输入流中取出数据
            while((hasRead=fis.read(b))>0){
                //每读取一次,即写入文件输入流,读了多少,就写多少。
                fos.write(b,0,hasRead);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            fis.close();
            fos.close();
        }
    }
}

运行程序可以看到输出流指定的目录下多了一个文件:newTest.txt, 该文件的内容和Test.txt文件的内容完全相同。FileWriter的使用方式和FileOutputStream基本类似。

2.3 缓冲流的使用

BufferedInputStream/BufferedReader, BufferedOutputStream/BufferedWriter

字节缓存流的用法(字符缓存流的用法和字节缓存流一致就不介绍了)

public class BufferedStreamTest {
    public  static void main(String[] args)throws IOException {
        FileInputStream fis=null;
        FileOutputStream fos=null;
        BufferedInputStream bis=null;
        BufferedOutputStream bos=null;
        try {
            //创建字节输入流
            fis=new FileInputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\Test.txt");
            //创建字节输出流
            fos=new FileOutputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\newTest.txt");
            //创建字节缓存输入流
            bis=new BufferedInputStream(fis);
            //创建字节缓存输出流
            bos=new BufferedOutputStream(fos);

            byte[] b=new byte[1024];
            int hasRead=0;
            //循环从缓存流中读取数据
            while((hasRead=bis.read(b))>0){
                //向缓存流中写入数据,读取多少写入多少
                bos.write(b,0,hasRead);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            bis.close();
            bos.close();
        }
    }
}

可以看到使用字节缓存流读取和写入数据的方式和文件流(FileInputStream,FileOutputStream)并没有什么不同,只是把处理流套接到文件流上进行读写。

上面代码中我们使用了缓存流和文件流,但是我们只关闭了缓存流。这个需要注意一下,当我们使用处理流套接到节点流上的使用的时候,只需要关闭最上层的处理就可以了。java会自动帮我们关闭下层的节点流。
### 2.4 转换流的使用 InputStreamReader/OutputStreamWriter

以获取键盘输入为例来介绍转换流的用法。java使用System.in代表输入。即键盘输入,但这个标准输入流是InputStream类的实例,使用不太方便,而且键盘输入内容都是文本内容,所以可以使用InputStreamReader将其包装成BufferedReader,利用BufferedReader的readLine()方法可以一次读取一行内容

public class InputStreamReaderTest {
    public  static void main(String[] args)throws IOException {
        try {
            // 将System.in对象转化为Reader对象
            InputStreamReader reader=new InputStreamReader(System.in);
            //将普通的Reader包装成BufferedReader
            BufferedReader bufferedReader=new BufferedReader(reader);
           String buffer=null;
           while ((buffer=bufferedReader.readLine())!=null){
            // 如果读取到的字符串为“exit”,则程序退出
               if(buffer.equals("exit")){
                   System.exit(1);
               }
               //打印读取的内容
               System.out.print("输入内容:"+buffer);
           }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
        }
    }
}

上面程序将System.in包装成BufferedReader,BufferedReader流具有缓存功能,它可以一次读取一行文本——以换行符为标志,如果它没有读到换行符,则程序堵塞。等到读到换行符为止。运行上面程序可以发现这个特征,当我们在控制台执行输入时,只有按下回车键,程序才会打印出刚刚输入的内容。

2.5 对象流的使用

ObjectInputStream/ObjectOutputStream

写入对象:


    public static void writeObject(){
        OutputStream outputStream=null;
        BufferedOutputStream buf=null;
        ObjectOutputStream obj=null;
        try {
  **加粗样式**          //序列化文件輸出流
            outputStream=new FileOutputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\myfile.tmp");
            //构建缓冲流
            buf=new BufferedOutputStream(outputStream);
            //构建字符输出的对象流
            obj=new ObjectOutputStream(buf);
            //序列化数据写入
            obj.writeObject(new Person("A", 21));//Person对象
            //关闭流
            obj.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

读取对象:

    /**
     * 读取对象
     */
    public static void readObject() throws IOException {
        try {
            InputStream inputStream=new FileInputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\myfile.tmp");
            //构建缓冲流
            BufferedInputStream buf=new BufferedInputStream(inputStream);
            //构建字符输入的对象流
            ObjectInputStream obj=new ObjectInputStream(buf);
            Person tempPerson=(Person)obj.readObject();
            System.out.println("Person对象为:"+tempPerson);
            //关闭流
            obj.close();
            buf.close();
            inputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

使用对象流的一些注意事项

  • 读取顺序和写入顺序一定要一致,不然会读取出错。
  • 在对象属性前面加transient关键字,则该对象的属性不会被序列化。

三 总结

https://www.cnblogs.com/hopeyes/p/9736642.html

1)明确要操作的数据是数据源还是数据目的(要读还是要写)

  • 源:InputStream  Reader
  • 目的:OutputStream  Writer

2)明确要操作的设备上的数据是字节还是文本

  • 源:
    字节:InputStream
    文本:Reader
  • 目的:
    字节:OutputStream
    文本:Writer

3)明确数据所在的具体设备

  • 源设备:
    硬盘:文件 File开头
    内存:数组,字符串
    键盘:System.in
    网络:Socket
  • 目的设备:
    硬盘:文件 File开头
    内存:数组,字符串
    屏幕:System.out
    网络:Socket

4)明确是否需要额外功能?

  • 需要转换——转换流 InputStreamReader OutputStreamWriter
  • 需要高效——缓冲流Bufferedxxx
  • 多个源——序列流 SequenceInputStream
  • 对象序列化——ObjectInputStream,ObjectOutputStream
  • 保证数据的输出形式——打印流PrintStream Printwriter
  • 操作基本数据,保证字节原样性——DataOutputStream,DataInputStream

参考:
https://blog.csdn.net/nightcurtis/article/details/51324105
https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484946&idx=1&sn=043b054de3aef29bf3ff80eea15c16fd&source=41#wechat_redirect
https://www.cnblogs.com/hopeyes/p/9736642.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值