节点流和处理流基本使用
文章目录
- 1. 基本介绍
- 2. 节点流和处理流一览图
- 3. 节点流和处理流的区别和联系
- 4. 处理流的功能主要体现在以下两个方面
- 5. 处理流 BufferedReader 和 BufferedWriter
- 6. 处理流-BufferedInputStream 和 BufferedOutputStream
- 7. 对象流-ObjectInputStream 和 ObjectOutputStream
- 8. 对象流介绍
- 9. 标准输入输出流
- 10. 转换流-InputStreamReader 和 OutputStreamWriter
- 11. 打印流-PrintStream和PrintWriter
1. 基本介绍
- 节点流可以从一个特定的数据源读写数据,如:
FileReader
、FileWriter
- 处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,也更加灵活,如:
BufferedReader
、BufferedWriter
2. 节点流和处理流一览图
3. 节点流和处理流的区别和联系
- 节点流是底层流/低级流,直接跟数据源相接
- 处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出
- 处理流(包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据
源相连【模拟修饰器设计模式】
4. 处理流的功能主要体现在以下两个方面
- 性能的提高:主要以增加缓冲的方式来提高输入输出的效率
- 操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使
用更加灵活方便
5. 处理流 BufferedReader 和 BufferedWriter
BufferedReader
和BufferedWriter
属于字符流,是按照字符来读取数据的关闭时处理流,只需要关闭外层流即可- 案例1:使用
BufferedReader
读取文本文件,并显示在控制台
public class BufferedReader_ {public static void main(String[] args) throws Exception {String filePath = "e:\\hello.txt";//创建bufferedReaderBufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));//读取String line; //按行读取, 效率高//说明//1. bufferedReader.readLine() 是按行读取文件//2. 当返回null 时,表示文件读取完毕while ((line = bufferedReader.readLine()) != null) {System.out.println(line);}//关闭流, 这里注意,只需要关闭 BufferedReader ,因为底层会自动的去关闭 节点流//FileReader。/* 源码public void close() throws IOException {synchronized (lock) {if (in == null)return;try {in.close();//in 就是我们传入的 new FileReader(filePath), 关闭了.} finally {in = null;cb = null;}}}*/bufferedReader.close();}
}
- 运行结果:
hello,你好呀。
- 案例2:使用
BufferedWriter
将 ”hello,兮动人”,写入到文件中
public class BufferedWriter_ {public static void main(String[] args) throws IOException {String filePath = "e:\\ok.txt";//创建BufferedWriter//说明://1. new FileWriter(filePath, true) 表示以追加的方式写入//2. new FileWriter(filePath) , 表示以覆盖的方式写入BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));bufferedWriter.write("hello, 兮动人!");bufferedWriter.newLine();//插入一个和系统相关的换行bufferedWriter.write("hello2, 兮动人!");bufferedWriter.newLine();bufferedWriter.write("hello3, 兮动人!");bufferedWriter.newLine();//说明:关闭外层流即可 , 传入的 new FileWriter(filePath) ,会在底层关闭bufferedWriter.close();}
}
-
运行后:
-
案例3:综合使用BufferedReader和BufferedWriter完成文本文件拷贝,注
意文件编码。
public class BufferedCopy_ {public static void main(String[] args) {//1. BufferedReader 和 BufferedWriter 是按照字符操作//2. 不要去操作 二进制文件[声音,视频,doc, pdf ], 可能造成文件损坏//BufferedInputStream//BufferedOutputStreamString srcFilePath = "e:\\hello.txt";String destFilePath = "e:\\hello2.txt";BufferedReader br = null;BufferedWriter bw = null;String line;try {br = new BufferedReader(new FileReader(srcFilePath));bw = new BufferedWriter(new FileWriter(destFilePath));//说明: readLine 读取一行内容,但是没有换行while ((line = br.readLine()) != null) {//每读取一行,就写入bw.write(line);//插入一个换行bw.newLine();}System.out.println("拷贝完毕...");} catch (IOException e) {e.printStackTrace();} finally {//关闭流try {if(br != null) {br.close();}if(bw != null) {bw.close();}} catch (IOException e) {e.printStackTrace();}}}
}
6. 处理流-BufferedInputStream 和 BufferedOutputStream
- 介绍 BufferedInputStream
- 介绍 BufferedOutputStream
- 案例:完成图片/音乐的拷贝(要求使用Buffered…流)
这块也可以拷贝图片、音乐和文本等
public class BufferedCopy02 {public static void main(String[] args) {String srcFilePath = "e:\\imgs\\xdr.png";String destFilePath = "e:\\imgs\\xdr2.png";//创建BufferedOutputStream对象BufferedInputStream对象BufferedInputStream bis = null;BufferedOutputStream bos = null;try {//因为 FileInputStream 是 InputStream 子类bis = new BufferedInputStream(new FileInputStream(srcFilePath));bos = new BufferedOutputStream(new FileOutputStream(destFilePath));//循环的读取文件,并写入到 destFilePathbyte[] buff = new byte[1024];int readLen = 0;//当返回 -1 时,就表示文件读取完毕while ((readLen = bis.read(buff)) != -1) {bos.write(buff, 0, readLen);}System.out.println("文件拷贝完毕~~~");} catch (IOException e) {e.printStackTrace();} finally {//关闭流 , 关闭外层的处理流即可,底层会去关闭节点流try {if(bis != null) {bis.close();}if(bos != null) {bos.close();}} catch (IOException e) {e.printStackTrace();}}}
}
7. 对象流-ObjectInputStream 和 ObjectOutputStream
看一个需求
- 将
int num = 100
这个int数据保存到文件中,注意不是100
数字,而是int 100
,并且,能够从文件中直接恢复int 100
- 将
Dog dog = new Dog("小黄", 3)
这个dog对象保存到文件中,并且能够从文件恢复 - 上面的要求,就是能够将基本数据类型或者对象进行序列化和反序列化操作
序列化和反序列化
- 序列化就是在保存数据时,保存数据的值和数据类型
- 反序列化就是在恢复数据时,恢复数据的值和数据类型
- 如果需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:
Serializable //这是一个标记接口,没有方法
Externalizable //该接口有方法需要实现,因此我们一般实现上面的Serializable接口
8. 对象流介绍
功能:提供了对基本类型或对象类型的序列化和反序列化的方法
- ObjectOutputStream 提供 序列化 功能
- ObjectInputStream 提供 反序列化 功能
- 案例1:使用
ObjectOutputStream
序列化基本数据类型和一个Dog
对象(name,age)
,并保存到data.dat
文件中
public class ObjectOutStream_ {public static void main(String[] args) throws Exception {//序列化后,保存的文件格式,不是存文本,而是按照他的格式来保存String filePath = "e:\\data.dat";ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));//序列化数据到 e:\data.datoos.writeInt(100);// int -> Integer (实现了 Serializable)oos.writeBoolean(true);// boolean -> Boolean (实现了 Serializable)oos.writeChar('a');// char -> Character (实现了 Serializable)oos.writeDouble(9.5);// double -> Double (实现了 Serializable)oos.writeUTF("兮动人");//String//保存一个dog对象oos.writeObject(new Dog("小狗", 10, "中国", "白色"));oos.close();System.out.println("数据保存完毕(序列化形式)");}
}class Dog implements Serializable {private String name;private int age;private String country;private String color;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getCountry() {return country;}public void setCountry(String country) {this.country = country;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public Dog(String name, int age, String country, String color) {this.name = name;this.age = age;this.country = country;this.color = color;}
}
- 案例2:使用
ObjectlnputStream
读取data.dat
并反序列化恢复数据
public class ObjectInputStream_ {public static void main(String[] args) throws ClassNotFoundException, IOException {//指定反序列化的文件String filePath = "e:\\data.dat";ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));// 读取//1. 读取(反序列化)的顺序需要和你保存数据(序列化)的顺序一致//2. 否则会出现异常System.out.println(ois.readInt());System.out.println(ois.readBoolean());System.out.println(ois.readChar());System.out.println(ois.readDouble());System.out.println(ois.readUTF());//dog 的编译类型是 Object , dog 的运行类型是 DogObject dog = ois.readObject();System.out.println("运行类型=" + dog.getClass());System.out.println("dog信息=" + dog);//底层 Object -> Dog// 这里是特别重要的细节://1. 如果我们希望调用Dog的方法, 需要向下转型//2. 需要我们将Dog类的定义,放在到可以引用的位置Dog dog2 = (Dog)dog;System.out.println(dog2.getName());//关闭流, 关闭外层流即可,底层会关闭 FileInputStream 流ois.close();}
}
注意事项和细节说明
1)读写顺序要一致
2)要求序列化或反序列化对象,需要实现Serializable
3)序列化的类中建议添加SerialVersionUID
,为了提高版本的兼容性
4)序列化对象时,默认将里面所有属性都进行序列化,但除了static
或transient
修饰的成员
5)序列化对象时,要求里面属性的类型也需要实现序列化接口
6)序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化
9. 标准输入输出流
public class InputAndOutput {public static void main(String[] args) {//System 类 的 public final static InputStream in = null;// System.in 编译类型 InputStream// System.in 运行类型 BufferedInputStream// 表示的是标准输入 键盘System.out.println(System.in.getClass());//1. System.out public final static PrintStream out = null;//2. 编译类型 PrintStream//3. 运行类型 PrintStream//4. 表示标准输出 显示器System.out.println(System.out.getClass());System.out.println("hello, 兮动人~");Scanner scanner = new Scanner(System.in);System.out.println("输入内容");String next = scanner.next();System.out.println("next=" + next);}
}
10. 转换流-InputStreamReader 和 OutputStreamWriter
- 先看一个文件乱码问题,引出学习转换流必要性
public class CodeQuestion {public static void main(String[] args) throws IOException {//读取e:\\a.txt 文件到程序//思路//1. 创建字符输入流 BufferedReader [处理流]//2. 使用 BufferedReader 对象读取a.txt//3. 默认情况下,读取文件是按照 utf-8 编码String filePath = "e:\\a.txt";BufferedReader br = new BufferedReader(new FileReader(filePath));String s = br.readLine();System.out.println("读取到的内容: " + s);br.close();}
}
- 如果把 a.txt 换成
GBK
格式,读出来的内容就会乱码
ANSI并不是某一种特定的字符编码,而是在不同的系统中,ANSI表示不同的编码。具体是要取决于操作系统,如果是中文操作系统ANSI表的是 GBK 编码格式。
- InputStreamReader:Reader的子类,可以将InputStream(字节流)包
装成(转换)Reader(字符流) - OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)
包装成Writer(字符流) - 当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文
问题,所以建议将字节流转换成字符流 - 可以在使用时指定编码格式(比如utf-8,gbk,gb2312,1SO8859-1等)
- 应用案例
- 编程将字节流
FilelnputStream
包装成(转换成)字符流InputStreamReader
,对文件进行读取(按照utf-8/gbk
格式),进而在包装成BufferedReader
/*** 演示使用 InputStreamReader 转换流解决中文乱码问题* 将字节流 FileInputStream 转成字符流 InputStreamReader, 指定编码 gbk/utf-8*/
public class InputStreamReader_ {public static void main(String[] args) throws IOException {String filePath = "e:\\a.txt";//解读//1. 把 FileInputStream 转成 InputStreamReader//2. 指定编码 gbk//InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");//3. 把 InputStreamReader 传入 BufferedReader//BufferedReader br = new BufferedReader(isr);//将2 和 3 合在一起BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "gbk"));//4. 读取String s = br.readLine();System.out.println("读取内容=" + s);//5. 关闭外层流br.close();}}
- 编程将字节流
FileOutputStream
包装成(转换成)字符流OutputStreamWriter
,对文件进行写入(按照gbk
格式,可以指定其他,比如utf-8
)
public class OutputStreamWriter_ {public static void main(String[] args) throws IOException {String filePath = "e:\\xdr.txt";String charSet = "utf-8";OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), charSet);osw.write("hi, 兮动人");osw.close();System.out.println("按照 " + charSet + " 保存文件成功~");}
}
11. 打印流-PrintStream和PrintWriter
- 演示PrintStream (字节打印流/输出流)
public class PrintStream_ {public static void main(String[] args) throws IOException {PrintStream out = System.out;//在默认情况下,PrintStream 输出数据的位置是 标准输出,即显示器/*public void print(String s) {if (s == null) {s = "null";}write(s);}*/out.print("john, hello");//因为print底层使用的是write , 所以我们可以直接调用write进行打印/输出out.write("兮动人,你好".getBytes());out.close();//我们可以去修改打印流输出的位置/设备//1. 输出修改成到 "e:\\f1.txt"//2. "hello, 兮动人~" 就会输出到 e:\f1.txt//3. public static void setOut(PrintStream out) {// checkIO();// setOut0(out); // native 方法,修改了out// }System.setOut(new PrintStream("e:\\f1.txt"));System.out.println("hello, 兮动人~");}
}
- 演示 PrintWriter 使用方式
public class PrintWriter_ {public static void main(String[] args) throws IOException {//PrintWriter printWriter = new PrintWriter(System.out);PrintWriter printWriter = new PrintWriter(new FileWriter("e:\\f2.txt"));printWriter.print("hi, 云兮动人~~~~");printWriter.close();//flush + 关闭流, 才会将数据写入到文件..}
}