Java的I/O建立于stream(流)之上,所有的输出流和输入流都有各自的相同的读写方法,这也是Java面向接口编程的优势,这也是面向对象编程思想里面“封装”的思想!
一、Java网络编程里几个“名词”和常识:
(1)过滤器(filter):可以串链到输入流或者输出流上。顾名思义,可以通过使用filter可以修改数据(加密、压缩)、或者转换数据格式;
(2)阅读器(reader)和writer(书写器):同filter类似,也可以串链到流上。不同的是,读写器只是用于读/写字符,而不是字节(流处理的数据类型是字节)【读写器可以认为是和流在统计level】。
注意:串链这个词很好,表示filter和读写器都可以像链表这种形式一样,一个接一个的调用!
(3)流是同步的:当线程请求一个流操作(读/写)数据时,它是阻塞的,不能做其他事情。(Java也支持使用通道和缓冲区的非阻塞I/O,不在讨论范围!)
二、JavaI/O类结构
首先摘录一些《Think in Java》的内容:
(1)自InputStream/Reader派生而来的类都有read()基本方法,自OutputStream/Writer派生而来的类都有write()方法。
(2)很少用单一的流来创建流对象,通过叠合多个对象来达到目的(装饰器设计模式,以后会专门开一个设计模式专题)!
InputStream的作用是从不同数据源获取数据,下面看看具体有哪些:
OutputStream类型:
(3)现在来看看“装饰器(filter)”:他有两个类,分别是FilterInputStream和FilterOutputStream,这两者分别从基类InputStream和OutputStream继承而来。
FilterInputStream类型:
FilterOutputStream类型:
(4)关于PrintStream和PrintWriter的比较
PrintStream有两个问题:
a. 它会捕捉所有的IOExceptions;
b. 为完全国际化,不能以平台无关的方式处理换行动作(我们经常看到的System.out.print()就是基于PrintStream的)
PrintStream是一个OutputStream,PrintWriter有一个接受OutputStream的构造器,因此完全可以把System.out转换成PrintWriter。
(5)Reader 和 Writer
目的:设计Reader 和 Writer的初衷是为了国际化,老式的I/O继承层次结构仅支持8位的字节流,不能不能处理16位的Unicode字符,Java的char类型也是Unicode类型。
适配器:为了将“字节”和“字符”的使用结合起来,可以使用InputStreamReader和OutputStreamWriter类将InputStream和OutputStream转换成Reader和Writer。
使用意见:尽量尝试使用Reader和Writer,不行则使用流式结构。
下面看看流和读/写器的对比:
相应的过滤器结构:
三、I/O操作实例
1. 输入文件:可以使用以String和File对象为参数的FileReader;为了提高速度,可以使用BufferedReader,示例如下:
package zy.io;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedInputFile {
public static void main(String[] args) throws IOException {
//用的是相对路径
System.out.print(read("src/zy/io/BufferedInputFile.java"));
}
public static String read(String filename) throws IOException {
BufferedReader reader = new BufferedReader(
new FileReader(filename));
String s;
StringBuilder builder = new StringBuilder();
while ((s = reader.readLine()) != null) {
builder.append(s + "\n");
}
reader.close();
return builder.toString();
}
}
2. 从内存输入:将内存中的某个数据发送到控制台
package zy.io;
import java.io.IOException;
import java.io.StringReader;
public class MemoryInput {
public static void main(String[] args) throws IOException {
StringReader reader = new StringReader(
BufferedInputFile.read("src/zy/io/MemoryInput.java"));
int c;
while ((c = reader.read()) != -1) {
System.out.print((char)c);
}
}
}
3. 格式化内存输入:使用DataInputStream类,这是面向字节的。这里提供两种方式,请见注释部分:
package zy.io;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
public class FormattedMemoryInput {
public static void main(String[] args) throws IOException {
DataInputStream in = new DataInputStream(new ByteArrayInputStream(
BufferedInputFile.read("src/zy/io/FormattedMemoryInput.java").getBytes()));
//available()的字面意思是:在不阻塞的情况下锁能读取的字节数!
while (in.available() != 0) {
System.out.print((char)in.readByte());
}
//任何字节的值都是合法的,返回值不能不用于检测输入是否结束,因此使用了try catch 块
/*try {
DataInputStream in = new DataInputStream(new ByteArrayInputStream(
BufferedInputFile.read("src/zy/io/FormattedMemoryInput.java").getBytes()));
while (true) {
System.out.print((char)in.readByte());
}
} catch (EOFException e) {
System.err.println("End of file");
}*/
}
}
4. 缓冲输出文件:当输出文件时,需要调用close()方法,因为在缓存区可能还有数据没有被写入;当然也可以调用flush()方法,强制清空,并将缓存的数据发送,一般情况下推荐close()就可以了,相当于一次flush(),而且流也关闭了,不会占据内存资源,但是当需要保存流的时候,就应该调用flush(),可以保证数据的完整性!
package zy.io;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
public class BasicFileOutput {
private static String file = "BasicFileOutput.out";
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(
new StringReader(BufferedInputFile.read("src/zy/io/BasicFileOutput.java")));
// PrintWriter writer = new PrintWriter(new
// BufferedWriter(new FileWriter(file)));
// 这是快捷方式,不用自己的进行缓存,依旧以缓存的模式
PrintWriter writer = new PrintWriter(file);
int lineNum = 1;
String s;
while ((s = reader.readLine()) != null) {
writer.println(lineNum++ + ": " + s);
}
//writer.flush();
writer.close();
System.out.println(BufferedInputFile.read(file));
}
}
先写这些吧,后续有什么补充在跟上!