Input and Output - Source and Destination
Java IO解决的问题是从一个source读取数据,和写数据到一个destination。在Java中常见的source和destination有下面几种:
- Files
- Pipes
- Network Connections
- System.in, System.out, System.error
- In-memory Buffers (e.g. arrays)
这里面除了In-memory Buffers
比较特殊,其它的(文件、管道、socket、设备等)其实在操作系统层面已经统一抽象为文件。
从source读取数据,写数据到destination是非常常见的需求:
对于上面的应用场景,Java提供引入流(Stream)的抽象,让从source中读写数据变得简单和统一:
Reading
open a stream
while more information
read information
close the stream
Writing
open a stream
while more information
write information
close the stream
其中根据读写数据的特点,又区分为二进制流(字节流)和文本流(字符流):
- 二进制流:字节流, 8-bit bytes; InputStream, OutputStream.
- 文本流:字符流, 16-bit characters; Reader, Writer.
Overview of the stream hierarchy
- Reader, root in unicode input hierarchy
- Writer, root in unicode output hierarchy
- InputStream, root in binary input hierarchy
- OutputStream, root in binary output hierarchy
所以上面的这两个Reading和Writing的步骤,使用Java IO就是如下的历程:
public class CopyBytes {
public static void main(String[] args) throws IOException {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("xanadu.txt");
out = new FileOutputStream("outagain.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}
public class CopyCharacters {
public static void main(String[] args) throws IOException {
FileReader inputStream = null;
FileWriter outputStream = null;
try {
inputStream = new FileReader("xanadu.txt");
outputStream = new FileWriter("characteroutput.txt");
int c;
while ((c = inputStream.read()) != -1) {
outputStream.write(c);
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}
}
The class hierarchies for readers and writers in java.io. Subclasses of Reader and Writer implement specialized streams and are divided into two categories: those that read from or write to data sinks (shaded) and those that perform some sort of processing (unshaded).
The class hierarchies for inputstreams and outputstreams in java.io. Subclasses of Inputstream and OutputStream implement specialized streams and are divided into two categories: those that read from or write to data sinks (shaded) and those that perform some sort of processing (unshaded). LineNumberInputStream is deprecated; use LineNumberReader instead.
TIPS InputStream或者Reader 是连接source的桥梁。OutputStream或者Writer是连接destination的桥梁。
Character Streams that Use Byte Streams
因为其实chars就是bytes的编码,所以Character Streams其实底层就是使用了Byte Streams来读取数据,然后按照指定的编码(如果应用没有指定那么就是file.encoding值)进行byte-to-character转换。所以Reader或者Writer的构造函数往往就是接收一个InputStream或者OutputStream,以及对应的编码(character)。如:
Reader reader = new InputStreamReader(inputStream, "UTF-8");
Writer writer = new OutputStreamWriter(outputStream, "UTF-8");
Character streams are often “wrappers” for byte streams. The character stream uses the byte stream to perform the physical I/O, while the character stream handles translation between characters and bytes. FileReader, for example, uses FileInputStream, while FileWriter uses FileOutputStream. There are two general-purpose byte-to-character “bridge” streams: InputStreamReader and OutputStreamWriter. Use them to create character streams when there are no prepackaged character stream classes that meet your needs.
Decorator Pattern and Java IO
Two issues with I/O
- What are you talking to (n).
- The way you are talking to it (m).
Solution no. 1
- Make a class for every combination
- n * m classes, not flexible, hard to extend
Solutions no. 2
- Java filter streams (decorators) are added dynamically to create the functionality needed.
- n + m classes
- Input decorator: FilterInputStream
- DataInputStream: Full interface for reading built-in types
- BufferedInputStream: Adds buffering to the stream (do this by default)
- LineNumberInputStream: Only adds line numbers
- PushbackInputStream: One-character push pack for scanners (lexers)
- Output decorator: FilterOutputStream
- DataOutputStream: Full interface for writing built-in types
- PrintStream: Allows primitive formatting of data for display (not printf!)
- BufferedOutputStream: Adds buffering to output (do this by default!)
应用的比较多的是BufferedInputStream/BufferedReader和BufferdOutputStream/BufferedWriter:
Reader reader = new BufferedReader(new FileReader(...));
Writer writer = new BufferedWriter(new FileWriter(...));
import java.io.*; // [Source: java.sun.com]
public class DataIODemo {
public static void main(String[] args) throws IOException {
// where to write to
DataOutputStream out = new DataOutputStream(
new FileOutputStream("invoice1.txt"));
// alternative also using a buffer decorator
DataOutputStream out = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("invoice1.txt")));
}
}
Java IO的设计目标和类体系结构
Java IO的设计目标如下:
- File Access
- Network Access
- Internal Memory Buffer Access
- Inter-Thread Communication (Pipes)
- Buffering
- Filtering
- Parsing
- Reading and Writing Text (Readers / Writers)
- Reading and Writing Primitive Data (long, int etc.)
- Reading and Writing Objects
这些目标自然而然的决定了Java现有的IO类体系结构: