[Java] Java IO 概况

Java IO 是 Java 的一套 API, 用于读入和写出数据(输入和输出)。Java IO API 位于 java.io package。实际上 java.io package 没有解决所有的输入输出情况,例如,web 页面没有包含在 Java IO package 里面,而是由 Java 企业版本的 servlet 和 HTTP package 处理。

Java IO package 关注文件、网络流(Network Stream), 内存缓冲区(internal memory buffer)的输入输出。Java IO package 没有包含用于打开网络套接字(Network socket) 的类。网络套接字由 Java Network API 打开,然后 Java IO 的 InputStream / OutputStream 从打开的套接字读入,或者向打开的套接字写出数据。

Java NIO 用于处理非阻塞的输入输出操作。

Input 和 Output

最常见的数据源或目的地有:

文件

管道

网络连接

内存缓冲区

System.in, System.out, System.error

本质的数据流动请求如下

Source -> Program -> Destination

Stream

Stream 是 Java IO 的核心概念。Stream  是一个无尽头的数据流,可以从一个 Stream 读取数据,也可以向一个 Stream 写入数据。Stream 没有下标,也不能向前向后地移动,和数组不一样。

Stream 可以简单分为基于字节(byte based),或者基于字符(character based)。

基于字节的 stream 一般叫做 xxxxxxStream,例如 InputStream, OutputStream。这些 stream 一次只读入或写出一个字节,除了 DataInputStream / DataOutputStream。DataInputStream / DataOutputStream 用于处理 int / long / boolean 等类型。

基于字符的 stream 一般叫做 xxxxxxReader 或 xxxxxxWriter。

程序通过 InputStream 或者 Reader 读入数据,通过 OutputStream 或者 Writer 写出数据。

Source -> InputStream / Reader -> Program

Program -> OutputStream / Writer -> Destination

如果需要写组件用于输入或输出,尽量让组件依赖于 InputStream / OutputSteam,而不是他们的具体子类,使得代码更加灵活应变。例如

InputStream is = new FileInputStream(filepath);
OutputSteam os = new FileOutputStream(filepath);

一次从文件读取一个字节是非常慢的,使用 BufferedInputStream 一次读取一大块数据会快很多。例子

InputStream is = new BufferedInputStream(new FileInputStream("/tmp/tony/a.txt"));

缓冲(buffer) 也适用于 OutputStream,用于批量写出到硬盘。

  Byte Based Character Based    
  Input Output Input Output comment
Basic InputStream OutputStream

Reader

InputStreamReader

Writer

OutputStreamWriter

 
Arrays          
Files FileInputStream FileOutputStream FileReader FileWriter  
Pipes          
Buffering BufferedInputStream BufferedOutputStream     In memory, better performance
Filter          
Parsing PushbackInpustream   PushbackReader    
String          
Data          
Data-formated          
Object          
Utilities          

InputStream 和 OutputStream

InputStream 是 Java IO API 中所有 input stream 的基础类。InputSream 下面的子类有 FileInputStream, BufferedInputStream。 InputStream 例子

            InputStream is = new FileInputStream("/tmp/tony/a.txt");
int data = is.read();
while(data != -1){
System.out.print((char)data);
data = is.read();
}

FileInputStream 是 InputStream 的子类。例子中省略了异常的处理。

当 read() 方法返回 -1 时,说明 stream 以及没有内容可以读取了。-1 是 int 值,而不是 byte 或 short 值。

read(byte[]) 方法一次读取字节数组,返回读入的字节数。read(byte[]) 比一次只读取一个字节的 read() 要快。每次都需要检查 read(byte[]) 的返回值,来了解读取的数据大小。

mark() 和 reset() 方法主要用于实现解释器,用到情况小。

OutputStream 是 Java IO API 中所有 output stream 的基础类。OutputStream 下面的子类有 FileOutputStream, BufferedOutputStrea。OutputStream 例子

            OutputStream os = new FileOutputStream("/tmp/tony/b.txt");
byte[] b = {'h', 'e', 'l', 'l'};
os.write(b);
os.close();

write(byte[]) 方法将 byte 数组中的所有字节写入到 OutputStream 中

flush() 方法,将已经写出 OutputSteam 的数据清刷(写出)到底层的数据目的地。例如,如果 OutputStream 是 FileOutputStream,写出到 FileOutputStream 的字节还没有全部写出到硬盘。即使 java 代码已经将数据写出到 FileOutputStream,数据可能还在缓存区而已。通过 flush() 方法,可以确保数据都清刷到硬盘(或网络)。

close() 方法,用于关闭 stream。通常位于 final 代码块。

Reader 和 Writer

Reader 和 Writer 在 Java IO 中的功能类似于 InputStream 和 OutputStream,差异点在于 Reader 和 Writer 基于字符。

Reader 是 Java IO API 中又有 reader 的基础类。Reader 下面的子类有 BufferedReader, InputStreamReader, StringReader。例子

            Reader reader = new FileReader("/tmp/tony/a.txt");
int data = reader.read();
while(data != -1){
System.out.print((char)data);
data = reader.read();
}

InputStream 一次返回 8 bit( 一个 byte ) 的值 (0 到 255)

Reader 一次返回 16 bit 的值 ( 0 到 65535), 可能是一个或多个 byte,取决于文本采用的编码格式。

Reader 可以套在 InputStream 外面,来读取字符。

            InputStream is = new FileInputStream("/tmp/tony/a.txt");
Reader rd = new InputStreamReader(is);

Writer 可以类似地套在 OutputStream 外面,写出字符。

            OutputStream os = new FileOutputStream("/tmp/tony/b.txt");
Writer wt = new OutputStreamWriter(os);
wt.write("qqq");
wt.close();

Reader / Writer 子类的的组装

            Reader reader = new BufferedReader(new FileReader("/tmp/tony/a.txt"));

            Writer writer = new BufferedWriter(new FileWriter("/tmp/tony/c.txt"));

参考资料

Java IO Tutorial, jenkov

上一篇:斯坦福第十七课:大规模机器学习(Large Scale Machine Learning)


下一篇:使用 Java 开发兼容 IPv6 的网络应用程序