首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java I/O 常用的实现类

Java I/O 常用的实现类

作者头像
搬砖俱乐部
发布2019-06-16 11:58:49
8650
发布2019-06-16 11:58:49
举报
文章被收录于专栏:BanzClubBanzClub

FileInputStream与FileoutputStream

FileInputStream类可以将一个文件的内容作为字节流读取,我们看一下源码:

  • FileDescriptor 文件描述符
  • FileChannel Java Nio FileChannel 是一个连接文件的通道,通过这个文件通道可以从文件读数据,向文件里写数据,是Java nio的替代方法,可以使用Java IO API进行读取文件
  • native操作
    • initIDs
    • open0 打开
    • available 剩余可用字节数;如遇结尾返回0;
    • read0 读取字节
    • close0 关闭
  • 构造:
    • 以文件路径构建
    • 以文件对象构建
    • 以文件描述符构建

FileoutputStream是使用字节流方式将数据写入文件,实现与FileinputStream一样,一个是字节流方式读文件,一个是字节流方式写文件。

需要注意的是,FileInputStream和FileoutputStream是直接从文件中读取数据到应用程序内存中,或直接从程序中写到文件上,没有缓冲区的概念(注:FileoutputStream的flush方法没有实现内容)。

FilterInputStream、FilterOutputStream与装饰者模式

查看FilterInputStream与FilterOutputStream的源码,我们并没有看出有什么特殊的实现,只是内置了InputStream和OutputStream,并在对应的方法上调用了实例in和实例out的方法,这就是装饰者模式。主要是提供与真实类一样的功能,并且将请求转给真实的类,并且在特定情况下可以扩展功能,这种扩展不会影响原类的功能。使用装饰器模式,感觉像实现了复杂一点的继承关系。

BufferedInputStream与BufferedOutputStream

BufferedInputStream增加了缓冲区,不像FileInputStream每次一个字节一个字节的读取,而是一次读取一块数据到内存缓冲区中,再从缓冲区中读取字节流,减少了访问磁盘的次数,而在内存缓冲区读取相当于内存级别的操作,所以,读取效率更快。BufferedInputStream是FilterInputStream的子类,也就是说,BufferedInputStream可以指定任意一个InputStream对象为装饰器的实际对象,这里可以理解成,即可以读取网络I/O,又可以读取磁盘I/O。

然后读一下源码看一下具体实现:

  • 设置缓冲区,通过byte[] buf(缓存数组)、pos(读取位置)、count(缓冲区最后一个有效索引+1)来控制缓冲区的读取位置和长度
  • 支持mark、reset方法,通过markpos(标记位置),marklimit(标记位置变为无效之前可读取的最大字节数限制),实现重读数组中的标记字节
    • mark记录标记位置
    • reset回到mark的位置重新读取
  • fill方法—填充缓冲区
    • 没启用mark,正常填充缓冲区,读取buffer.length-pos长度数据,pos正常都会归0,向缓冲区的0位置开始填充整个缓冲区长度的数据
    • 启用mark,会保留markpos到pos中间的字节,然后继续填满缓冲区
    • 如果,markpos是buffer的0索引位置,则需要扩展缓冲区大小,来读取新的字节,因为标记字节就已经占满了缓冲区,扩充环翠区的大小为原缓冲区长度与marklimit之间的最小值,直到扩展到最大缓冲区大小MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8
    • 如果读取,超过marklimit,则将标记置为无效

BufferedOutputStream增加了缓冲区,可以每次向缓冲区中写字节流,然后再统一写到磁盘或者网络,减少IO的次数,提升效率。

BufferedOutputStream的flush方法,会调用一次flushBuffer方法,执行装饰器真实类的写方法,并且调用真实类的flush方法。(FileOutputStream方法的flush方法有什么作用?)

DataInputStream与DataOutputStream是一个与平台无关的输入输出流的类,提供基本数据类型的输入和输出操作。查看源码这两个类实现了DataInput和DataOutput接口,并且继承自FilterInputStream和FilterOutputStream。所以这两类仍然使用了装饰器模式,并且实现DataInput与DataOutput中的基本数据类型的输入和输出操作。

RandomAccessFile与常见的输入输出类不同,查看类图可以看出,它实现了DataInput和DateOutput接口,而底层的读、写等方法都是JNI方法,所以它与其他的输入输出类不同,而且它同时提供读写两种操作,因为操作比较灵活,所以命名为Random访问文件。

PipedInputStream与PipedOutputStream是建立Java两个线程之间的管道,两个线程通过建立起来的管道进行输入和输出字节流。

查看源码可以看出:

  • PipedInputStream与PipedOutputStream的数据读写,实际上是通过PipedInputStream的receive和read两个同步方法实现,使用了经典的notify和wait模型;
  • 输入输出中间有缓冲区byte[] buffer,使用int类型的in和out表示读写下标;
  • 使用readSide和writeSide代表读写两个线程;
public class PipStream {    PipedInputStream inputStream;    PipedOutputStream outputStream;    public void read() {        inputStream = new PipedInputStream(4096);        outputStream = new PipedOutputStream();        try {            outputStream.connect(inputStream);        } catch (IOException e) {            e.printStackTrace();        }        Thread thread1 = new Thread(() -> {            try {                int data = inputStream.read();                while (data != -1) {                    System.out.println(data);                    data = inputStream.read();                }            } catch (IOException e) {                e.printStackTrace();            }        });        thread1.start();        Thread thread2 = new Thread(() -> {            int i = 0;            while (true) {                if (i >= 100) {                    break;                }                try {                    outputStream.write(1);                } catch (IOException e) {                    e.printStackTrace();                }                i++;                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        });        thread2.start();    }    public static void main(String[] args) {        new PipStream().read();    }}

ObjectInputStream与ObjectOutputStream实现的是对基本类型或对象的序列化与反序列化操作,也是装饰器模式,可以将对象或者基本类型的数据存入文件或者网络中,再通过文件和网络重新读取序列化之前的基本类型或对象数据。应用场景包括实现对象序列化为二进制数据,再反序列化从二进制数据变成对象。

public class ObjectStream {    private static String readPath = "C:\\Users\\Administrator\\Desktop\\person.txt";    public static void main(String[] args) {        Person person = new Person();        person.setPwd("1234");        person.setUid("4321");        try {            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(readPath));            objectOutputStream.writeObject(person);            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(readPath));            Object object = objectInputStream.readObject();            Person p = (Person) object;            System.out.println("pwd:" + p.getPwd() + ",uid" + p.getUid());        } catch (IOException | ClassNotFoundException e) {            e.printStackTrace();        }    }}

InputStreamReader与OutputStreamWriter是将基于字节流的InputStream和OutputStream转化成基于字符流的Reader和Writer,构造方法需要指定字符编码,以防止字节转成字符时候乱码,查看源码发现,底层都是通过StreamEncoder来实现的,包括读取策略,写入策略,字符编码,缓冲区等。

FileReader、FileWriter与FileInputStream、FileoutputStream类似,都是从一个文件中进行读取和写入,只不过FileReader和FileWriter是以字符形式,FileReader和FileWriter是InputStreamReader和OutputStreamWriter的子类,只是包装了一下FileInputStream、FileoutputStream类。

PipedReader、PipedWriter可以将管道中的数据以字符形式读取和写入,其工作原理与PipedInputStream和PipedOutputStream类似。

BufferedReader、BufferedWriter为Reader、Writer类提供缓冲区,实现原理与BufferedInputStream和BufferedOutputStream类似,但不相同,主要区别就是一个读取字节,一个读取字符(文本),BufferedReader还提供readLine方法,使读取文本更加方便,BufferedWriter也可以写入换行符(换行符是在构造方法中获取系统的换行标识符)。

FilterReader、FilterWriter是装饰器类,用来扩展Reader、Writer,目前来看没有什么实际使用场景。

其他特殊IO类

ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter是字节数组和字符数组的输入输出对象,它们都是通过读取和写入字节或字符数组实现。(注:关闭对于这四个类来说,没有意义)

LineNumberReader是BufferedReader的子类,主要是增加了LineNumber的概念。

SequenceInputStream是Java提供的可以将两个或者多个InputStream合并成一个,按照顺序分别读取每个输入流中的数据。

PushbackInputStreamPushbackReader是IO API提供的具有回退机制的输入字节流,输入字符流。


  1. https://docs.oracle.com/javase/8/docs/api/java/io/FileInputStream.html
  2. https://blog.csdn.net/ai_bao_zi/article/details/81205286
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 BanzClub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档