Java 输入/输出(I/O)学习笔记 -- 流
在 Java API 中,可以从其中读入一个字节序列的对象称做输入流,而可以向其中写入一个字节序列的对象称做输出流。这些字节序列的来源地和目的地可以是文件,而且通常都是文件,但是也可以是网络连接,甚至是内存块。抽象类 InputStream 和 OutputStream 构成了输入 / 输出(I/O)类层次结构的基础。
InputStream 类有一个抽象方法:
abstract int read()
这个方法将读入一个字节,并返回读入的字节,或者在遇到输入源结尾时返回 -1。在设计具体的输入流类时,必须覆盖这个方法以提供适用的功能。
与此类似,OutputStream 类定义了下面的抽象方法:
abstract void write(int b)
它可以向某个输出位置写出一个字节。
read 和 write 方法在执行时都将阻塞,直至字节确实被读入或写出。这就意味着如果流不能被立即访问(通常是因为网络连接忙) ,那么当前的线程将被阻塞。这使得在这两个方法等待指定的流变为可用的这段时间里,其他的线程就有机会去执行有用的工作。
available 方法使我们可以去检查当前可读入的字节数量,当完成对流的读写时,应该通过调用 close 方法来关闭它,这个调用会释放掉十分有限的操作系统资源。如果一个应用程序打开了过多的流而没有关闭,那么系统资源将被耗尽。关闭一个输出流的同时还会冲刷用于该输出流的缓冲区:所有被临时置于缓冲区中,以便用更大的包的形式传递的字符在关闭输出流时都将被送出。特别是,如果不关闭文件,那么写出字节的最后一个包可能将永远也得不到传递。当然,我们还可以用 flush 方法来人为地冲刷这些输出。
FileInputStream 和 FileOutputStream 可以提供附着在一个磁盘文件上的输入流和输出流,而你只需向其构造器提供文件名或文件的完整路径名。例如:
FileInputStream fin = new FileInputStream("test.dat");
这行代码可以访问用户目录下名为”test.dat”的文件。
与抽象类 InputStream 和 OutputStream 一样,这些类只支持在字节级别上的读写。也就是说,我们只能从 fin 对象中读入字节和字节数组。
正如 FileInput Stream 没有任何读入数值类型的方法一样,DataInputStream也没有任何从文件中获取数据的方法。Java 使用了一种灵巧的机制来分离这两种职责。某些流(例如 FileInputStream 和由URL 类的 openStream 方法返回的输入流)可以从文件和其他更外部的位置上获取字节,而其他的流(例如 DataInputStream 和 PrintWriter)可以将字节组装到更有用的数据类型中。我们必须对二者进行组合。例如,为了从文件中读入数字,首先需要创建一个FileInputStream,然后将其传递给 DataInputStream 的构造器:
FileInputStream fin = new FileInputStream("test.dat");
DataInputStream din = new DataInputStream(fin);
int i = din.readInt();
我们还可以通过嵌套过滤器来添加多重功能。例如,流在默认情况下是不被缓冲区缓存的,也就是说,每个对 read 的调用都会请求操作系统再分发一个字节。相比之下,请求一个数据块并将其置于缓冲区中会显得更加高效。如果我们想使用缓冲机制,以及用于文件的数据输入方法,那么就需要使用下面这种相当恐怖的构造器序列:
DataInputStream din = new DataInputStream(
new BufferedInputStream(
new FileInputStream("test.dat")));
在其他编程语言的流类库中,诸如缓冲机制和预览等细节都是自动处理的。因此,相比较而言,Java 就有一点麻烦,它必须将多个流过滤器组合起来。但是,这种混合并匹配过滤器类以构建真正有用的流序列的能力,将带来极大的灵活性。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。