??流是一个抽象的概念,代表了数据的无结构化传递。流的本质是数据在不同设备之间的传递。在Java中,数据的读取和写入都是以流的方式进行的。
??在Java中,根据数据流向的不同,可以将流分为输入流和输出流;根据单位的不同,可以将流分为字节流和字符流;根据等级的不同,可以将流分为节点流和处理流。
输入流:输入流用于将数据从控制台、文件、网络等外部设备输入应用程序进程中
输出流:输出流用于将应用程序进程中的数据输出到控制台、文件、显示器等中。
(1)字节流:字节流以字节(8个bit)为单位对数据进行读写操作,因此主要用于处理二进制数据。在Java中使用InputStream和OutputStream处理字节数据。抽象类InputStream和OutputStream构成了输入/输出(IO)类层次结构的基础。
??如果想要读写字符串和数字,就需要功能更加强大的子类,例如DataInputStream和DataOutputStream可以以二进制格式读写所有的基本Java类型,ZipInputStream和ZipOutputStream可以以常见的ZIP压缩格式读写文件。
(2)字符流:字符流以字符为单位对数据进行读写操作,一次读取或写入都是以16bit为单位进行的。Java中的字符采用Unicode编码,一个字符占用2字节。字符流主要用于处理文本数据的读写,在处理过程中需要进行字符集的转换。在Java中使用Reader、Writer处理字符数据。
close()、flush()
??当你完成对流的读写时,应该通过调用close方法来关闭它,这个调用会释放掉十分有限的操作系统资源。如果一个应用程序打开了过多的流而没有关闭,那么系统资源将被耗尽。关闭一个输出流的同时还会冲刷用于该输出流的缓冲区:所有被临时置于缓冲区中,以使用更大的包的形式传递的字符在关闭输出流时都将被送出。特别是,如果不关闭文件,那么写出字节的最后一个包可能将永远得不到传递。当然,我们还可以用flush方法来人为地冲刷这些输出。
一般只有数据量特别大的时候才需要在中间的时候就flush(),否则一般只需要close()就可以了
字节流和字符流的基本方法类似,都含有read(),write(),close(),输出流都有flush()
对于文本输出,推荐使用PrintWriter,这个类拥有以文本格式打印字符串和数字的方法,它的输出功能强大。与字节流类似,字符流也可以包装BufferedWriter提高访问数据的效率。但是由于字节流本身没有缓冲区,故缓冲字节流相较于字节流,效率提升就比较大;而字符流本身是有缓冲区的,所以说缓冲字符流对于字符流的效率提升就不是很大。
??节点流是低级流,直接与数据源相接,对数据源上的流进行读写。
??处理流是高级流,采用修饰器模式对节点流进行了封装,不直接与数据源相连,主要用于消除不同节点流的实现差异,提供更方便的方法来完成数据的输入和输出。
??例如,FileInputStream、FileOutputStream、FileReader、FileWriter属于节点流;BufferInputStream、BufferOutputStream、BufferReader、BufferWriter属于处理流。
相对于节点流,处理流有如下特性:
比如,节点流 FileInputStream和FileOutputStream只支持在字节级别上的读写,没有任何读入和写入数值类型的方法;与之相反,处理流中的DataInputStream和DataOutputStream没有任何从文件中获取数据或写入数据的方法。Java程序员需要对二者进行组合,例如实现从文件中读入数字,具体代码如下:
FileInputStream fin = new FileInputStream("emplyee.dat");
DataInputStream din = new DataInputStream(fin);
double s = din.readDouble();
??处理流又称过滤流,是对已存在的节点流或其他处理流的进一步处理。FilterInputStream和FilterOutputStream及其子类都都是处理流,可以向原生的字节流添加额外的功能。我们可以通过嵌套过滤器来添加多重功能。
DataInputStream din = new DataInputStream(new BuffedInputStream(new FileInputStream("employ.dat")));
上面的代码就产生了一个可读取数据的带缓冲机制的输入流,带有缓冲机制可以使的数据的获取更加高效。
操作系统可以利用虚拟内存实现将一个文件或者文件的一部分“映射”到内存中。然后这个文件就可被都当作内存数据来访问,比传统的文件要快得多,这种技术就是内存映射文件技术。
Java中的nio包支持内存映射文件技术,在Java中将一个文件映射到内存并操作共分为如下3步:
(1)从文件中获得一个通道
(2)调用FileChannel的map方法将文件映射到虚拟内存
可以通过mode参数指定映射模式。
(3)调用MappedByteBuffer的put(byte[] src)向内存映射文件中写入数据,调用get(int index)获取文件中对应索引的数据,以字节形式返回。
(1)字节流可以处理Unicode字符吗?
??字节流在处理数据时,是以字节为单位进行读写的。对于Unicode字符,一个字符可能由一个或多个字节组成,具体取决于所使用的字符编码。如果直接使用字节流处理Unicode字符,可能会导致字符编码不一致,从而出现乱码或错误解释的情况。
??字符流(Reader和Writer)在设计上更适合处理字符数据,它们能够理解并正确处理字符编码,提供了更高层次的抽象,使得处理Unicode字符更为方便和安全。
??因此,虽然字节流理论上可以处理Unicode字符,但为了确保正确处理字符编码、避免乱码和数据错误解释,更推荐使用字符流进行Unicode字符的读写操作。
(2)字节流与字符流的区别
本篇博客参考了王磊的<<Offer来了>>第二版