Java IO流全面解析:典型使用方式与分类详解
javaio流的典型使用方式有几种
Java中的IO流分为两类。
一类是输入流。
所有输入流都直接或间接继承自InputStream抽象类,输入流的read方法读取字节数据;
第二个是输出流。
所有输出流都直接或间接继承自OutputStream抽象类,并且可以通过write方法写入到Word中。
截面数据。
在Java的IOStream类中,大多数输入流和输出流都是成对存在的,即有一个XXXInputStream,就有一个XXXOutputStream,反之亦然。
SequenceInputStream和StringBufferInputStream是特殊情况。
没有对应的SequenceOutputStream类和StringBufferOutputStream类,很多IO操作都会抛出IOException,比如读、写、关闭。
Java的IO流有以下几种常见的输入流。
由于每个输入流都有自己对应的输出流,因此这里不再列出输出流的继承结构图。
1.ByteArrayInputStream&ByteArrayOutputStream:
需要传递一个字节数组作为数据源,当执行读操作时,将从这个数组中读取数据。
顾名思义,它是一个基于字节数组的简单输入流。
很明显,如果在构造函数中将null作为字节数据传递,那么在执行读取的操作过程中将出现NullPointerException。
,但在构造函数的初始化阶段不会抛出异常;对应的ByteArray为O;utputStream内部使用字节数组来存储写操作期间写入的数据。
在构造函数中,您可以读取其内部字节可以传递一个大小来指定数组的大小。
如果不指定,则默认初始化字节数组。
为32个字节,当通过连续写入的方式向ByteArrayOutputStream写入数据时,如果其内部字节数组的剩余空间无法存储需要写入的数据,则会将其用于存储所有需要写入的数据。
通过调用内部的确保容量方法来扩展内部维护的字节数组,因此无需担心。
像IndexOutOfBoundsException这样的异常是由于内部字节数组太小引起的。
2.FileInputStream&FileOutputStream
FileInputStream可以使用文件作为数据源,读取文件中的流,并通过文件对象或文件路径进行初始化。
在其构造函数中,如果传入的文件对象(或其相对文件路径表示的文件对象)不存在或者是目录而不是文件或者由于其他原因无法打开读取数据,则在初始化阶段会抛出错误n会发生异常;与FileInputStream对应的是FileOutputStream。
数据可以通过FileOutputStream写入文件,并且还需要通过文件对象或文件路径进行初始化,就像传入的文件对象(或其代表文件对象的关联文件路径)是一个文件而不是那里。
由于其他原因无法创建用于写入数据的目录或文件,初始化阶段会抛出FileNotFoundException异常。
3.PipedInputStream&PipedOutputStream
PipedInputStream和PipedOutputStream通常用于两个线程之间的管道通信。
已完成。
操作,并在另一个线程中执行PipedInputStream的读取操作。
您可以通过在构造函数中传递相应的流来绑定PipedInputStream和PipedOutputStream,也可以通过它们的Connect方法绑定两者。
一旦两者绑定,PipedInputStream的read方法就会自动读取PipedOutputStream写入的数据。
PipedInputStream的读操作是阻塞的。
当执行PipedOutputStream的写操作时,PipedOutputStream会自动读取另一个线程中PipedOutputStream写入的内容。
如果PipedOutputStream还没有执行写操作写入数据,那么PipedInputStream的read方法将会阻塞。
线程运行PipedInputStream的read方法,直到读取数据。
单独使用PipedInputStream或PipedOutputStream是没有意义的。
如果两者通过Connect方法连接并绑定(或者将相应的流传递给构造函数),则会触发IOException。
:管道未连接。
4.ObjectInputStream&ObjectOutputStream
ObjectOutputSStream有一系列writeXXX方法。
可以在其构造函数中包含OutputStream,以便轻松地将基本类型的数据和字符串写入指定的输出流,例如WriteBoolean、WriteChar、WriteInt、WriteLong、WriteFloat、WriteDouble、WriteCharts、WriteUTF等。
另外,ObjectOutputStream还有一个writeObject方法。
传递给WriteObject方法的类型必须实现Serialized接口,以便在执行WriteObject操作时,对象被序列化为流并返回指定的输出。
写在流上。
与ObjectOutputStream对应的是ObjectInputStream。
ObjectInputStream有readXXX系列方法,与OutputStream中的writeXXX系列方法完全匹配,它们专门用于读取通过writeXXX写入OutputStream的数据。
5.SequenceInputStream
SequenceInputStream主要是将两个(或多个)InputStream合并为一个InputStream,例如两个InputStream分别传入in1和in2,在读取操作时会先读取in1。
如果in1读完,就会读in2。
了解了SequenceInputStream的功能是将两个输入流合并为一个输入流后,我们就可以理解为什么没有对应的SequenceOutputStream类了,因为将输出流拆分为多个输出流是没有意义的。
6.StringBufferInputStream
StringBufferInputStream允许您通过在内部调用读取字符串的charAt方法时将字符串传递给构造函数来读取字节。
与SequenceInputStream类似,StringBufferInputStream没有对应的OutputStream,即没有StringBufferOutputStream类。
Java没有设计StringBufferOutputStream类的原因也很简单。
我们假设StringBufferOutputStream应该在内部写入数据,并通过执行写入操作来更新其内部的String对象,但这可以通过StringBuilder来实现,这是没有意义的,因为一旦我们在String构造函数中创建了String就可以直接传入一个字节。
array来创建,简单明了,所以不需要设计StringBufferOutputStream。
StringBufferInputStream类本身有问题。
它不能很好地将字符数组转换为字节数组,因此该类被Java标记为已弃用。
官方建议是使用StringReader来代替。
7.FilterInputStream&FilterOutputStream
FilterInputStream包含其他输入流,具体来说,需要在其构造函数中传递一个InputStream并将其保存在其name字段中,FilterInputStream只是重写了所有方法,它之所以称为简单重写是因为在每个重写的函数,它会从存储在字段中的内部InputStream中调用相应的方法,比如重写read方法时,in.read()方法。
刚刚内部打电话。
FilterInputStream的子类可以在保持接口不变的情况下重写一些方法来实现某个功能(例如,它的一些子类可以通过使用缓存来优化读取效率)或者其他一些额外的实用方式可以提供。
因此,在使用时,FilterInputStream可以给传入的InputStream一些额外的功能,即它包装了构造函数传递的InputStream,并使用特定的装饰模式。
如果单看FilterInputStream类,那么Self类的重要性并不大,因为。
它仅通过内部字段覆盖一些方法。
但如果FilterInputStream与其子类结合使用,则非常有用。
例如,FilterInputStream有两个子类,BufferedInputStream和DataInputStream,下面将详细介绍它们。
BufferedInputStream优化读取操作。
每个读操作都会读取一大块数据,然后将其放入内部维护的字节数组缓冲区中。
当外部调用BufferedInputStream的read方法时,首先从缓冲区中读取数据,从而避免了重复的实际读取操作,BufferedInputStream没有向外界暴露任何额外的方法,但其内部的read方法已经被优化得更多。
执行读操作时高效。
DataInputStream有点类似于ObjectInputStream。
基本类型的数据可以通过一些ReadAccess方法来读取,这是非常有用的方法。
8.BufferedInputStream和BufferedOutputStream
上面提到,BufferedInputStream的构造函数中需要传入一个InputStream。
每次读取操作时都会缓冲一个字节数组。
从此buf中读取数据。
从buf中读取数据花费并不多。
如果没有数据读入buf,则执行其内部绑定的InputStream的read方法,一次性读取一大块数据来填充buf缓冲区。
buffer缓冲区默认大小为8192字节,即8K。
在构造函数中,我们还可以传递一个size来指定缓冲区的大小。
因为当我们对BufferedInputStream执行读操作时,我们经常会从位于指定InputStream中的缓冲区中读取数据。
大大减少了实际读取操作的次数,提高了读取效率。
BufferedInputStream的反面是BufferedOutputStream。
在BufferedOutputStream的构造函数中,我们需要传递一个OutputStream,从而将BufferedOutputStream绑定到OutputStream。
BufferedOutputStream缓冲区内部包含一个字节缓冲区。
执行写操作时,首先将要写入的数据缓存在一起,并且对buf的大小进行限制,即8KB,当然也可以在构造函数中传递size来指定buf的大小。
除非指定大小,否则缓冲区不会自动扩展,因此它的大小是有限的,所以会有一个缓冲区满的时候,BufferedOutputStream的flushBuffer方法会被调用。
该方法实际上会通过调用其绑定的OutputStream的Write方法将数据写入到buf中,并将buf的指针重置为零(可以看作是清除buf中的数据)。
如果希望buffer缓冲区中的数据真正写入到OutputStream中,可以调用flush方法,flush方法内部会调用flushBuffer方法。
由于buf的存在,实际对OutputStream的写入操作次数会大大减少,写入效率会得到优化。
java的io流和nio有什么区别?
下面这篇文章介绍了Java的IO流和NIO的区别:传统的IO模型有很多类;这里,我直接参考优秀的思维导图,不再赘述。通过测试文件复制性能;传统IO和NIO在处理大文件方面都有各自的优势,但NIO并没有明显优于传统IO。
NIO的核心在于Channel管道和Buffer缓冲区的协同使用,支持双向数据读写。
Buffer是Buffer类的抽象,ByteBuffer是处理字节数据最常用的实现类。
Channelpipeline负责数据传输,bufferbuffer用于不直接处理数据的数据操作。
ChannelChannel通过transfer()方法进行数据传输。
直接和间接中介机构;使用间接媒介更为有效。
Scatter和Gather实现分散读取和聚集写入。
文件描述;了解用户空间和内核空间以及I/O操作等基本概念。
阻塞非阻塞;和I/O复用模型分别对应不同的I/O操作方式。
使用NIO进行网络通信;蔚来表示网络层的非阻塞特性。
NIO阻塞和非阻塞模式是通过客户端和服务器代码实现的。
总结一下NIO的使用要点,包括管道、DataGramChannel等。
NIO是学习Netty的一个重要知识点。
java中的io流有哪些
Java中的IO流是指不同输入输出资源的输入或输出操作,而流是一种抽象描述。指程序中传输数据的方法。
IO流的分类:(1)按数据流向:输入流、输出流(2)按流数据格式:字符流、字节流(3)按封装过程,流数据:节点流(低层)溪流);最基本的处理流类型(高级流)简单介绍:•InputStream/Reader:所有输入流的基类;前者是字节输入流;接下来是一个角色。
输入流。
•OutputStream/Writer:所有输出流的基类;前者是字节输出流,后者是字符输出流。
如何理解输入流与输出流概念
读入内存的东西就是输入流从内存写入记录存储和输出流的东西我们把记录存储当作原来的,所以会有一种混乱的感觉,javaio流可以分为输入流和输出流就是将源数据读取到缓冲区中,输出流就是将缓冲区中的数据按照指定的格式写入到指定的位置,所以也是如此。意味着同时使用这两个流。
例如,要上传文件,必须先使用输入流将要上传的文件读取到缓冲区中,然后使用输出流将文件写入到网络服务器上上传成功的位置;如果是文件下载,首先获取输入流,读取网络服务器中的文件,然后使用输出流写入本地文件,这也是一个很好的例子,首先使用输入流进行读取和写入然后使用输出流写出来,你可以先尝试一个小例子,它会帮助你理解javaio