Java中的流按照功能可以分为节点流和处理流。其中节点流是直接用来访问数据源,而数据源又分为文件、内存、管道(线程间通信使用),所以就需要不同的类来进行处理。每次从数据源中读取的数据单位又可以分为字节和字符。
节点流:可以从一个特定的数据源读写数据,如FileReader、FileWriter等(程序用于直接操作目标设备所对应的类)
处理流:是“连接”已存在的流(节点流和处理流)之上,为程序提供强大的读写功能,更加灵活。 程序通过一个间接流类去调用节点流类,以达到更加灵活方便地读写各种类型的数据,这个间接流类就是处理流(也叫包装流,对节点流进行包装)如BufferedReader 、BufferedWriter等
处理流中可以封装一个节点流,该节点流可以是任意的,只要是处理流父类的子类!
节点流和处理流流览图
处理流设计模式模拟
public abstract class Reader_ {//抽象类
public void readFile() {
}
public void readString() {
}
}
class FileReader_ extends Reader_ {
public void readFile() {
System.out.println("对文件进行读取...");
}
}
class StringReader_ extends Reader_ {//节点流l
public void readString() {
System.out.println("读取字符串...");
}
}
/**
* 做成处理流,也叫包装流
*/
class BufferedReader_ extends Reader_ {
private Reader_ reader_;//属性就是Reader_类型
public BufferedReader_(Reader_ reader_) {
this.reader_ = reader_;
}
//让方法更加灵活,多次读取文件 扩展
public void readFiles(int num) {
for (int i = 0; i < num; i++) {
reader_.readFile();
}
}
//扩展readString,批量处理字符串数据
public void readStrings(int num) {
for (int i = 0; i < num; i++) {
reader_.readString();
}
}
@Override
public void readFile() {
reader_.readFile();
}
@Override
public void readString() {
reader_.readString();
}
}
class Test_ {
public static void main(String[] args) {
//使用节点流
BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_());
bufferedReader_.readFile();
bufferedReader_.readFiles(10);
BufferedReader_ bufferedReader_1 = new BufferedReader_(new StringReader_());
bufferedReader_1.readStrings(10);
}
}
处理流的功能:
常见的两个字符处理流(属于字符流,按照字符来读取数据的)
BufferedReader:从字符输入流中读取文本并缓冲字符,以便有效地读取字符,数组和行
可以通过构造函数指定缓冲区大小也可以使用默认大小。
BufferedWriter:将文本写入字符输出流,缓冲字符,以便有效地写入单个字符,数组和字符串。
因为有缓冲区所以很效率比没有缓冲区的很高,在关闭处理流时,是需要关闭外层流即可(底层会自动关闭节点流的)
BufferedReader类下有一个Reader属性,它用于存放Reader类下的流,包装操作
BufferedReader提供了两个构造器,根据不同的场景进行选择
示例
使用BufferedReader读取文本文件,并显示在控制台,readLine按行读取文件(BufferedReader类下的方法),当返回null时,表示读取完毕。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReader_ {
public static void main(String[] args) throws IOException {//throws对异常进行处理的方式
String filePath = "E:\\Utility.java";
//创建BufferedReader对象
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
//BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));追加模式
//读取
String line;//按行读取,效率高
while ((line = bufferedReader.readLine())!=null){
System.out.println(line);
}
bufferedReader.close();
}
}
此时控制台输出E盘下的Utility.java的内容
BufferedWriter类中的Writer属性与BufferedReader中的Reader属性同理!
BufferedWriter提供了两个构造器,根据不同的场景进行选择
通过BufferedWriter写入文件字符串,此代码演示使用的是writer(String str),writer可以写入多种数据,具体方法可进行百度或者查看JDK文档
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWRITER_ {
public static void main(String[] args) throws IOException {//throws对异常进行处理
String filePath = "E:\\hello.txt";
//创建一个BufferedWriter
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
bufferedWriter.write("hello1");
bufferedWriter.newLine();//插入一个换行
bufferedWriter.write("hello2");
bufferedWriter.newLine();//插入一个换行
bufferedWriter.write("hello3");
bufferedWriter.close();
}
}
此时E盘下的hello.txt文本内容为:
hello1
hello2
hello3
切换FileWriter的构造器,可以将覆盖模式改为追加模式
将D盘下的hello.txt文本拷贝到E盘下
import java.io.*;
public class bufferedCopy_ {
public static void main(String[] args) throws IOException {
String srcFilePath = "D:\\hello.txt";//源
String destFilePath = "E:\\hello.txt";//要拷贝的目录
BufferedReader bufferedReader1 = new BufferedReader(new FileReader(srcFilePath));
BufferedWriter bufferedReader2 = new BufferedWriter(new FileWriter(destFilePath));
String temp;
while ((temp = bufferedReader1.readLine())!=null){
bufferedReader2.write(temp);
bufferedReader2.newLine();//换行
}
bufferedReader1.close();
bufferedReader2.close();
System.out.println("拷贝成功");
}
}
注意:如果拷贝的是二进制文件,则会乱码损毁(BufferedReader和BufferedWriter不要去操作二进制文件)
按照字节进行处理,常见的两个字节处理流(属于字节流,读取二进制数据)
由此流览图可知字节处理流可字符处理流类似,构造器中是各自父类或子类的实现对象!
将D盘下的mbg图片拷贝到E盘下
演示使用BufferedInputStream和BufferedOutputStream拷贝二进制文件
import java.io.*;
public class bufferedCopy {
public static void main(String[] args) {
String srcPath = "D:\\mbg.png";//要拷贝的文件
String destPath = "E:\\mbg.png";//要拷贝到哪里
BufferedInputStream bufferedInputStream1 = null;
BufferedOutputStream bufferedOutputStream2 = null;
try {
bufferedInputStream1 = new BufferedInputStream(new FileInputStream(srcPath));
bufferedOutputStream2 = new BufferedOutputStream(new FileOutputStream(destPath));
byte[] bytes = new byte[1024];
int readLen = 0;
while ((readLen = bufferedInputStream1.read(bytes))!=-1){
bufferedOutputStream2.write(bytes,0,readLen);
}
System.out.println("拷贝成功");
} catch (IOException e) {
e.getMessage();//输出异常
} finally {
try {
bufferedInputStream1.close();//关闭流,释放资源
bufferedOutputStream2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
在关闭处理流时,是需要关闭外层流即可(底层会自动关闭节点流的)
当我们在 bufferedReader.close() 处下断点时
一路真正代码执行,发现底层会自动调用close方法对节点流进行关闭