IO流
Java IO流是实现输入/输出的基础。
Java把不同的输入/输出源(键盘,文件,网络连接等)抽象为"流",Stream。
通过流的方式使用相同的方式来访问不同的输入/输出源。
stream是从起源(source)到接收(sink)的有序数据。
传统流类型都在 java.io 包中。
流的分类
输入输出流
按照流的流向分为输入流和输出流。是以内存的角度来划分。
输入流: 只能读取数据,不能写入。由InputStream 和 Reader作为基类
输出流: 只能写入数据,不能读取。由OutputStream 和 Writer 作为基类
字节流和字符流
字节流: 操作数据单元为8位字节,由 InputStream 和 OutputStream作为基类
字符流:操作数据单元为16位字符,由 Reader 和 Writer 作为基类
节点流和处理流
按角色分为节点流和处理流。
从一个特定的IO设备(磁盘,或网络)读写数据的流,称为节点流,节点流也被称为低级流(Low Level Stream)。
处理流是对节点流的封装。称为高级流,包装流。
使用装饰器设计模式。
InputStream和Reader
InputStream和Reader都是输入流的抽象基类。
都实现了下面方法
- read(): 可以读取单个字符或字节,
- read(byte[] b): 读取 b.length 个字节
- read(byte[] b, int off, int len): 读取 len 个字节,从 off 位置开始读
- mark(): 记录指针当前位置记录一个标记
- markSupported(): 是否支持 mark操作
- reset():将指针重新定位到上一次记录mark的位置
- skip(): 指针向前移动 n个字节/字符
FileInputStream 和 FileReader是两个读取文件的输入流。是 InputStream和 Reader的子类。
FileInputStream fis = new FileInputStream("ReadMe.txt");
byte[] fbuff = new byte[1024];
int hasRead = 0;
while ((hasRead = fis.read(fbuff)) > 0){
System.out.println(new String(fbuff, 0, hasRead));
}
fis.close();
程序里打开的 IO资源不属于内存里的资源, 垃圾回收机制无法回收该资源, 所以要显式的关闭IO资源,调用 fis.close()。
InputStream 和 Reader都实现了AutoCloseable 接口, 因此可以通过自动关闭资源的 try 语句来关闭IO流。
public abstract class InputStream implements Closeable {
}
public interface Closeable extends AutoCloseable {
}
OutputStream 和 Writer
OutputStream 和 Writer都是输出流的抽象基类。
都提供了下面方法:
- write(int c): 指定字符/字节输出
- write(byte[] buf): 数组输出
- write(byte[] buf, int off, int len): 将数组中 off 开始, 长度为len 输出
Writer还包括了支持 String 参数的 writer() 方法。
FileOutputStream 和 FileWriter 用来文件输出。
try (FileInputStream fis1 = new FileInputStream("ReadMe.txt");
FileOutputStream fos = new FileOutputStream("newFIle.txt")){
byte[] fbuff = new byte[32];
int hasRead = 0;
while ((hasRead = fis1.read(fbuff)) > 0){
fos.write(fbuff, 0, hasRead);
}
}
catch (IOException e){
e.printStackTrace();
}
关闭输出流除了保证资源被回收之外,还可以将输出缓冲区的数据flush到物理节点中。在执行close()之前,自动执行输出流的flush()。
如果是字符串内容,可以直接使用Writer();
try (FileWriter fileWriter = new FileWriter("t.txt")){
fileWriter.write("a\r\n");
fileWriter.write("c test\r\n");
}
catch (IOException e){
e.printStackTrace();
}
处理流用法
使用处理流包装节点流,对外提供更加方便的输入/输出。
节点流的构造器是以物理IO节点为参数的。
处理流的构造器不是物理IO节点,而是已经存在的流。
下面例子 PrintStream 就是处理流,输出更加方便。
try(FileOutputStream fos = new FileOutputStream("abc.txt");
PrintStream ps = new PrintStream(fos)){
ps.println("test字符串");
ps.println(new FileTest());
}
catch (IOException e){
e.printStackTrace();
}
关闭资源时,只需要关闭最上层处理流即可, 关闭处理流时,自动关闭该处理流包装的节点流。
IO流
JAVA IO流体系提供了近40个类。
转换流
IO体现提供了两个转换流, 将字节流转换为字符流。
InputStreamReader 将字节输入流转为字符输入流
OutputStreamWriter 将字节输出流转为字符输出流
try (InputStreamReader reader = new InputStreamReader(System.in);
BufferedReader bufferedReader = new BufferedReader(reader)
){
String line = null;
while ((line = bufferedReader.readLine()) != null){
if(line.equals("exit")){
System.exit(1);
}
System.out.println(line);
}
}
catch (IOException e){
e.printStackTrace();
}
System.in 代表标准输入,即键盘输入,这个输入流是 InputStream 类的实例, 使用 InputStreamReader 转为字符输入流。
将 Reader 包装为 BufferedReader, 使用它的 readLine() 方法一次读一行。
推回输入流
PushbackInputStream, PushbackReader 这两个是推回输入流。
提供了 unread () 方法。
这两个输入流都带一个推回缓冲区, 将指定数组内容推回到该缓冲区。
调用 read()时, 先从推回缓冲区读取, 未装满时,再从原缓冲区读取。
需要指定推回缓冲区的大小, 默认为1。
下面例子找到 test 字符串, 输出之前的内容
try (PushbackReader pushbackReader = new PushbackReader(new FileReader("abc.txt"), 32)){
char[] buf = new char[32];
String lastConntent = "";
int hasRead = 0;
while ((hasRead = pushbackReader.read(buf)) > 0){
String content = new String(buf, 0, hasRead);
int lastIndex = (lastConntent + content).indexOf("test");
if(lastIndex > 0){
pushbackReader.unread((lastConntent + content).toCharArray());
if(lastIndex > 32){
buf = new char[lastIndex];
}
pushbackReader.read(buf, 0, lastIndex);
System.out.println(new String(buf, 0, lastIndex));
System.exit(0);
}
else {
System.out.println(lastConntent);
lastConntent = content;
}
}
}
catch (IOException e){
e.printStackTrace();
}