1.处理流的用法
使用处理流时的典型思路是,使用处理流来包装节点流,程序通过处理流来执行输入/输出功能,让节点流与底层的I/0设备、文件交互。
实际上,识别处理流非常简单,只要流的构造器参数不是一个物理节点,而是已经存在的流,那么这种流就一定是处理流;而所有节点流都是直接以物理IO节点作为构造器参数的。
优势:
①对开发人员来说,使用处理流进行输入/输出操作更简单;
②使用处理流的执行效率更高。
示例:使用PrintStream处理流来包装OutputStream
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
public class PrintStreamTest {
public static void main(String[] args) throws IOException {
//定义一个节点输出流
FileOutputStream fos = new FileOutputStream("test.txt");
// 使用处理流PrintStream包装上面的节点流(传入上述节点流作为构造器参数)
PrintStream ps = new PrintStream(fos);
// 使用处理流PrintStream执行输出
ps.println("普通字符串");
// 直接使用PrintStream输出对象
ps.println(new PrintStreamTest());
ps.close(); //关闭处理流即可,包装的节点流会被系统自动关闭。
}
}
输出:将字符串和上面类对象存入到test.txt文件中。
注:先定义了一个节点输出流FileOutputStream,然后程序使用printStream包装了该节点输出流,最后使用Printstream输出字符串、输出对象…PrintStream的输出功能非常强大,前面程序中一直使用的标准输出
System.out的类型就是PrintStream。关闭处理流即可,包装的节点流会被系统自动关闭。
2.输入/输出流体系
注:通常来说,我们认为字节流的功能比字符流的功能强大,因为计算机里所有的数据都是二进制的,而字节流可以处理所有的二进制文件一一但问题是,如果使用字节流来处理文本文件,则需要使用合适的方式把这些字节转换成字符,这就增加了编程的复杂度。所以通常有一个规则:如果进行输入/输出的内容是文本内容,则应该考虑使用字符流;如果进行输入/输出的内容是二进制内容,则应该考虑使用字节流。
以数组为物理节点的节点流:字节流以字节数组为节点,字符流以字符数组为节点;这种以数组为物理节点的节点流除了在创建节点流对象时需要传入一个字节数组或者字符数组之外,用法上与文件节点流完全相似。与此类似的是,字符流还可以使用字符串作为物理节点,用于实现从字符串读取内容,或将内容写入字符串(用StringBuffer充当字符串)的功能。
示例:使用字符串作为物理节点的字符输入/输出流的用法。
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
public class StringNodeTest {
public static void main(String[] args) throws IOException {
// 1.从字符串中读取内容
String src = "从明天起,做一个幸福的人\n"
+ "喂马、劈柴,周游世界\n"
+ "从明天起,关心粮食和蔬菜\n"
+ "我有一所房子,面朝大海,春暖花开\n"
+ "从明天起,和每一个亲人通信\n"
+ "告诉他们,我的幸福\n";
char[] buffer = new char[32];
int hasRead = 0;
StringReader sr = new StringReader(src);
// 循环读取字符串
while((hasRead = sr.read(buffer)) > 0){
System.out.print(new String(buffer, 0, hasRead));
}
// 2.将内容写入字符串中
// 创建StringWriter时,实际上以一个StringBuffer作为输出节点
// 下面指定的20就是StirngBuffer的初始长度
StringWriter sw = new StringWriter();
//调用StringWriter的方法执行输出
sw.write("有一个美丽的新世界\n");
sw.write("它在远方等我\n");
sw.write("那里有天真的孩子\n");
sw.write("还有姑娘的酒窝\n");
System.out.println("-----下面是sw字符串节点里的内容-------");
// 使用toString() 方法返回StringWriter字符串节点的内容
System.out.println(sw.toString());
}
}
输出:
从明天起,做一个幸福的人
喂马、劈柴,周游世界
从明天起,关心粮食和蔬菜
我有一所房子,面朝大海,春暖花开
从明天起,和每一个亲人通信
告诉他们,我的幸福
-----下面是sw字符串节点里的内容-------
有一个美丽的新世界
它在远方等我
那里有天真的孩子
还有姑娘的酒窝
注意:上面程序与前面使用FileReader和FileWriter的程序基本相似,只是在创建StringReader和Stringwriter对象时传入的是字符串节点,而不是文件节点。由于string是不可变的字符串对象,所以stringwriter使stringBuffer作为输出节点。
3.转换流
用于实现将字节流转换成字符流:
InputstreamReader将字节输入流转换成字符输入流,
OutputStreamwriter将字节输出流转换成字符输出流。
下面以获取键盘输入为例来介绍转换流的用法。Java使用System.in代表标准输入,即键盘输入,但这个标准输入流是Inputstream类的实例,使用不太方便,而且键盘输入内容都是文本内容,所以可以使用InputStreamReader将其转换成字符输入流,普通的Reader读取输入内容时依然不太方便,将普通的Reader再次包装成BufferedReader,利用BufferedReader的readLine()方法可以一次读取一行内容。
示例:读取键盘输入,逐行打印
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class KeyinTest {
public static void main(String[] args) throws IOException {
//将System.in对象转换成Reader对象
InputStreamReader reader = new InputStreamReader(System.in);
//将普通的Reader包装成BufferedReader
BufferedReader br = new BufferedReader(reader);
String buffer = null;
//采用循环方式逐行的读取
while((buffer = br.readLine()) != null){
//如果读取的字符串为“exit”,则程序退出
if(buffer.equals("exit")){
System.exit(1);
}
//打印读取的内容
System.out.println("输入内容为:" + buffer);
}
}
}
输出:输入一行文本后,点击回车将输入的内容输出。
4.推回输入流
import java.io.FileReader;
import java.io.IOException;
import java.io.PushbackReader;
public class PushbackTest {
public static void main(String[] args) throws IOException {
//创建一个PushbackReader对象,指定推回缓冲区的长度为64
PushbackReader pr = new PushbackReader(new FileReader("D:\\workspace02\\study\\src\\com\\oath\\demo03\\PushbackTest.java"), 64);
char[] buf = new char[32];
// 用以保存上次读取的字符串内容
String lastContent = "";
int hasRead = 0;
// 循环读取文件内容
while((hasRead = pr.read(buf)) > 0){
System.out.println("hasRead:" + hasRead);
//将读取的内容转换成字符串
String content = new String(buf, 0, hasRead);
int targetIndex = 0;
// 将上次读取的字符串和本次读取的字符串拼起来
// 查看是否包含目标字符串,如果包含目标字符串
if((targetIndex = (lastContent + content).indexOf("new PushbackReader")) > 0){
// 将文本内容和上次内容一起推回缓冲区
pr.unread((lastContent + content).toCharArray());
//指定读取前面len个字符
int len = targetIndex > 32 ? 32 : targetIndex;
// 再次读取指定长度的内容(就是目标字符串之前的内容)
pr.read(buf, 0, len);
// 打印读取的内容
System.out.println(new String(buf, 0, len));
System.exit(0);
} else {
//打印上次读取内容
System.out.print(lastContent);
//将本次内容设为上次读取的内容
lastContent = content;
}
}
pr.close();
}
}
输出:(只会输出目标字符串前面内容)
package com.oath.demo03;
import java.io.FileReader;
import java.io.IOException;
import java.io.PushbackReader;
public class PushbackTest {
public static void main(String[] args) throws IOException {
//创建一个PushbackReader对象,指定推回缓冲区的长度为64
PushbackReader pr =