Java IO
Reference
[1] http://www.cnblogs.com/youxia/p/java007.html
Byte stream and Character stream
在 Java 中如果要把流中的数据按字节来访问,就应该使用 InputStream 和 OutputStream,如果要把流中的数据按字符来访问,就应该使用 Reader 和 Writer。用来输入的两个类 InputStream 和 Reader 主要定义了read()方法,而用来输出的两个类 OutputStream 和 Writer 主要定义了write()方法。所不同者,前者操作的是字节,后者操作的是字符。很显然,一次处理一个字节效率是及其低下的,所以read()和write()还有别的重载版本:
int read(byte[] b)
int read(byte[] b, int off, int len)
void write(byte[] b)
void write(byte[] b, int off, int len)
int read()
int read(char[] cbuf)
int read(char[] cbuf, int off, int len)
void write(int c)
void write(char[] cbuf)
void write(char[] cbuf, int off, int len)
void write(String str)
void write(String str, int off, int len)
字节流和字符流并不是完全对立的存在,其实字符流是在字节流上更高层次的封装。在底层,一切数据都是字节,但是经过适当的封装,可以把这些字节解释成字符。而且,并不是所有的 Reader 都是可以像 FileReader 那样直接创建的,有时,只能拿到一个可以读取字节数据的 InputStream,却需要在它之上封装出一个 Reader,以方便按字符的方式读取数据。
URL cnblogs = new URL("http://www.cnblogs.com/");
InputStream in = cnblogs.openStream();
Reader reader = new InputStreamReader(in);
所以, InputStreamReader 是沟通字节流和字符流的桥梁。同样的桥梁还用用于输出的 OutputStreamWriter
InputStream、OutputStream、Reader 和 Writer 是抽象的,根据不同的数据来源和目的又有不同的具体类。结合平时使用计算机的经验,我们也可以想到其它一些不同的数据来源和目的,比如从内存中读取字节或把字节写入内存,从字符串中读取字符或者把字符写入字符串等等,还有从管道中读取数据和向管道中写入数据等等。根据不同的数据来源和目的,可以有这样一些具体类:FileInputStream、ByteArrayInputStream、PipedInputStream、FileOutputStream、ByteArrayOutputStream、PipedOutputStream、FileReader、StringReader、CharArrayReader、PipedReader、FileWriter、StringWriter、CharArrayWriter、PipedWriter等。从这些类的命名可以看出,凡是以Stream结尾的,都是操作字节的流,凡是以 Reader 和 Writer 结尾的,都是操作字符的流。只有 InputStreamReader 和 OutputStreamWriter 是例外,它是沟通字节和字符的桥梁。
An InputStream is the raw method of getting information from a resource. It grabs the data byte by byte without performing any kind of translation. If you are reading image data, or any binary file, this is the stream to use.
A Reader is designed for character streams. If the information you are reading is all text, then the Reader will take care of the character decoding for you and give you unicode characters from the raw input stream. If you are reading any type of text, this is the stream to use.
You can wrap an InputStream and turn it into a Reader by using the InputStreamReader class.
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
Various APIs
向流中写入对象和读取对象,操作的肯定是字节流而不是字符流,所以只有 ObjectInputStream 和 ObjectOutputStream,而没有相应的 Reader 和 Writer 版本。再例如打印,操作的肯定是输出流,所以只有 PrintStream 和 PrintWriter,没有相应的输入流版本。
在这些类中,可以通过 PrintStream 和 PrintWriter 向流中写入格式化的文本,也可以通过 DataInputStream 和 DataOutputStream 从流中读取或向流中写入原始的数据,还可以通过 ObjectInputStream 和 ObjectOutputStream 从流中读取或写入一个完整的对象。如果要从流中读取格式化的文本,就必须使用 java.util.Scanner 类了。
使用 DataInputStream 和 DataOutputStream 只能写入和读取原始的数据类型的数据,如byte、char、short、float等,如果要读取和写入复杂的对象就不行了,比如java.math.BigDecimal。这个时候就需要使用 ObjectInputStream 和 ObjectOutputStream 了。所有需要写入流和从流读取的 Object 必须实现Serializable接口,然后调用 ObjectInputStream 和 ObjectOutputStream 的writeObject()方法和readObject()方法就可以了
与以二进制格式写入和读取数据相对的,就是以文本的方式写入和读取数据。PrintStream 和 PrintWriter 中的 Print 就是代表着输出能供人读取的数据。比如浮点数3.14可以输出为字符串"3.14"。利用 PrintStream 和 PrintWriter 中提供的大量print()方法和println()方法就可以做到这点,利用format()方法还可以进行更加复杂的格式化。对于 PrintStream 和 PrintWriter,我们用得最多的就是基于命令行的标准输入输出,也就是从键盘读入数据和向屏幕写入数据。