缓冲流

:::tips

缓冲流是对4个基本的 FileXxx 流的增强,所以也是4个流,按照数据类型分类:

  • 字节缓冲流: BufferedInputStream , BufferedOutputStream
  • 字符缓冲流: BufferedReader , BufferedWriter

    缓冲流的基本原理:

  • 在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率

image.png :::

字节缓冲流

:::tips

字节输出缓冲流 BufferedOutputStream

  • BufferedOutputStream 继承OutputStream,,操作时还是使用OutputStream的write方法
  • 构造方法

    • BufferedOutputStream(OutputStream out) 参数要一个基本的流,最终靠基本的流去操作文件

      字节输入缓冲流 BufferedInputStream

  • BufferedInputStream 继承InputStream,操作还是使用InputStream的read方法

  • 构造方法:

    • BufferedInputStream(InputStream in) 参数要一个基本的流,靠基本的流去操作文件 :::

      字符缓冲流

      :::tips

      字符输出缓冲流 BufferedWriter

  • BufferedWriter 继承了Writer,可以使用父类Writer中的write方法

  • 构造方法:
    • BufferedWriter(Writer out) 参数要传入基本流,靠基本流来操作文件
  • 特有方法:

    • newline() 换行

      字符输入缓冲流 BufferedReader

  • BufferedReader 继承了Reader,可以使用父类Reader中的read方法

  • 构造方法:
    • BufferedReader(Reader in) 参数要传入基本流,靠基本流来操作文件
  • 特有方法

    • String readLine() 读取一行数据返回,读不到时返回null :::

      缓冲流性能对比

      :::tips
  • 读写一个字节,使用缓冲流,可以明显提高效率

  • 读写一个字节数组,基本流和缓冲流差别不大
  • 缓冲流读写效率高,尽量使用缓冲流去代替基本流的使用 :::

    转换流

    :::tips

    概述

  • 计算机要准确的存储和识别各种字符集符号,需要进行字符编码

    输入转换流 InputStreamReader

  • InputStreamReader 继承 Reader

    • 可以使用平台默认编码 或者 指定编码 读取字符
  • InputStreamReader(InputStream in) 使用默认编码读取数据
  • InputStreamReader(InputStream in, String charsetName) 使用指定编码读取数据

    输出转换流OutputStreamWriter

  • OutputStreamWriter 继承 Writer

    • 可以使用平台默认编码 或者 指定编码 写出字符
  • OutputStreamWriter(OutputStream out) 使用默认编码写数据
  • OutputStreamWriter(OutputStream out, String charsetName) 使用指定编码写数据 :::

    对象流(序列化流)

    :::tips

    对象操作流分为两类

  • ObjectOutputStream 对象输出流

  • ObjectInputStream 对象输入流

    对象操作流API

  • 对象输出流

    • ObjectOutputStream(OutputStream out) 对象输出流, 把对象以字节的形式写到本地文件
    • public void writeObject(Object obj) 写一个对象到文件中
  • 对象输入流

    • ObjectInputStream(InputStream in) 对象输入流, 把写到本地文件中的对象读到内存中
    • public Object readObject() 读取文件中的对象数据到文件中

      对象流细节

  • 使用对象输出流将对象保存到文件时会出现NotSerializableException异常

    • 解决办法:需要让类实现Serializable接口
  • 用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类结构,读取数据会会出问题,会抛出InvalidClassException异常
    • 解决办法:给对象所属的类加一个 serialVersionUID 属性
  • 如果一个对象中的某个成员变量的值不想被序列化,那么给成员变量加transient关键字,该成员变量就不会被序列化到文件中 :::

    打印流

    :::tips

    字节打印流: PrintStream

  • 继承自FileOutputStream,write()方法和 FileOutputStream 流一样,可以写出字节或者字节数组

  • 特有的 println() 和 print() 方法,根据参数写出数据

    字符打印流: PrintWriter

  • 继承自Writer,write()方法和 Writer 流一样,可以写出字符或者字符数组或者字符串。

  • 特有的 println() 和 print() 方法,根据参数写出数据

  • System.out.println()输出语句中的out对象,其实就是一个PrintStream类的对象

  • System类内置了一个PrintStream对象,用于将数据快速打印到控制台

PrintStream 的API

构造器
  • PrintStream(File file) 创建PrintStream, 指定打印的目的地
  • PrintStream(String fileName) 创建PrintStream, 指定打印的目的地

    特有方法

  • print(Xxx x) 不换行打印,参数写什么,就输出什么

  • println(Xxx x) 换行打印,参数写什么,就输出什么

    PrintWriter 和 PrintStream 用法几乎一样 只不过PrintStream是操作字节,PrintWriter是操作字符

    :::

    属性集

    :::tips

  • Properties 类表示属性集。他是一个特殊的集合,可以结合IO流操作

  • Properties实现了Map接口,可以当做Map集合使用
  • Properties可以结合流进行数据读写,可以把集合中的数据保存到流中,也可以从流中来加载数据

    Properties作为集合的特有方法

  • Object setProperty(String key, String value) 添加键和值,键和值都是String类型,键存在就覆盖值

  • String getProperty(String key) 通过键获取值,如果键不存在,返回null
  • Set stringPropertyNames() 获取所有的键

    Properties和IO流结合的方法

  • void load(Reader reader) 使用字符输入流 加载 键值对 到Properties中

  • void store(Writer writer, String comments) 使用字符输出流将Properties中的键值对 保存 到文件中
  • void load(InputStream inStream) 使用字节输入流 加载 数据到Properties中
  • void store(OutputStream out, String comments) 使用字节输出流将Properties中的数据保存到文件 :::

    IO流异常处理

    :::tips

    JDK7增加 try-with-resource 语句来处理资源,该语句确保了每个资源在语句结束时关闭

  1. try(创建流对象,多个语句使用分号隔开) {
  2. 可能出现异常的代码;
  3. } catch(异常类名 变量名) {
  4. 异常的处理代码;
  5. }

自动关闭流,释放资源 :::

  1. /*
  2. 目标:学习字节缓冲流的使用
  3. 1.字节缓冲输入流:
  4. BufferedInputStream
  5. 2.特点:
  6. 缓冲流以Buffered开头,用法和FileInputStream一样。
  7. 缓冲流底层使用数组作为缓冲区,能提高读写的效率。
  8. 3.构造方法:
  9. BufferedInputStream(InputStream in)
  10. */
  11. public static void main(String[] args) throws Exception {
  12. //创建输入流对象
  13. BufferedInputStream input = new BufferedInputStream(
  14. new FileInputStream("Day11BufferedIO\\A\\a.txt")
  15. );
  16. byte[] arr = new byte[1024];
  17. int len;
  18. while ((len = input.read(arr)) != -1) {
  19. System.out.println(new String(arr, 0 ,len));
  20. }
  21. input.close();
  22. }
  1. /*
  2. 目标:学习字节缓冲流的使用
  3. 1.字节缓冲输出流:
  4. BufferedOutputStream
  5. 2.特点:
  6. 缓冲流以Buffered开头,用法和FileOutputStream一样。
  7. 缓冲流底层使用数组作为缓冲区,能提高读写的效率。
  8. 3.构造方法:
  9. BufferedOutputStream(OutputStream out)
  10. */
  11. public static void main(String[] args) throws Exception {
  12. //创建输出流对象
  13. BufferedOutputStream outPut = new BufferedOutputStream(
  14. new FileOutputStream("Day11BufferedIO\\A\\a.txt", true)
  15. );
  16. //写入数据
  17. outPut.write("爪哇程序员".getBytes());
  18. outPut.close();
  19. }
  1. /*
  2. 目标:学习字符缓冲流的使用
  3. 字符输入缓冲流:BufferedReader
  4. 特点:
  5. 继承自Reader,用法和FileReader一样。
  6. 底层使用缓冲数组读取数据,效率高。
  7. 构造方法:
  8. BufferedReader(Reader in)
  9. 特有方法:
  10. String readLine() 读取一行数据,读取不到返回null
  11. */
  12. public static void main(String[] args) throws Exception {
  13. BufferedReader reader = new BufferedReader(
  14. new FileReader("Day11BufferedIO\\A\\b.txt")
  15. );
  16. String line;
  17. //一次读取一行,到返回null结束
  18. while ((line = reader.readLine()) != null) {
  19. System.out.println(line);
  20. }
  21. reader.close();
  22. }
  1. /*
  2. 目标:学习字符缓冲流的使用
  3. 字符输出缓冲流:BufferedWriter
  4. 特点:
  5. 继承自Reader,用法和FileWriter一样。
  6. 底层使用缓冲数组读取数据,效率高。
  7. 构造方法:
  8. BufferedWriter(Writer out)
  9. 特有方法:
  10. void newLine() 写一个换行符,相当于写出"\r\n"
  11. 注意:
  12. 使用BufferedWriter写出数据后,记得调用flush或者close
  13. */
  14. public static void main(String[] args) throws Exception {
  15. BufferedWriter writer = new BufferedWriter(
  16. new FileWriter("Day11BufferedIO\\A\\b.txt", true)
  17. );
  18. writer.write("爪哇程序运行");
  19. writer.newLine();
  20. writer.write("爪哇程序运行");
  21. writer.close();
  22. }
  1. //DEA中默认使用UTF-8编码,如果在IDEA中读取其他编码的文件,就容易乱码
  2. public static void main(String[] args) throws Exception {
  3. InputStreamReader reader = new InputStreamReader(
  4. new FileInputStream("Day11BufferedIO\\A\\gbk_file.txt"), "GBK"
  5. );
  6. char[] arr = new char[1024];
  7. int len;
  8. while ((len = reader.read(arr)) != -1) {
  9. System.out.println(new String(arr, 0, len));
  10. }
  11. reader.close();
  12. }
  1. /*
  2. 练习文件的编码转换
  3. 需求:读取GBK编码的文本文件gbk_file.txt,转换为UTF-8编码的文本文件utf8_file.txt。
  4. 分析:
  5. 使用GBK编码读取文件内容。
  6. 使用UTF-8编码写字符数据到文件。
  7. 循环读写
  8. */
  9. public class DemoFileCode {
  10. public static void main(String[] args) throws Exception {
  11. InputStreamReader reader = new InputStreamReader(
  12. new FileInputStream("Day11BufferedIO\\A\\gbk_file.txt"), "GBK"
  13. );
  14. OutputStreamWriter writer = new OutputStreamWriter(
  15. new FileOutputStream("Day11BufferedIO\\A\\utf8_file.txt"), "UTF-8"
  16. );
  17. char[] arr = new char[1024];
  18. int len;
  19. while ((len = reader.read(arr)) != -1) {
  20. writer.write(arr, 0, len);
  21. }
  22. reader.close();
  23. writer.close();
  24. }
  25. }
  1. /*
  2. 目标:使用对象输出流将内存中的对象写到文件中。
  3. ObjectOutputStream (对象输出流/序列化流)
  4. 继承自OutputStream,可以将内存中的对象数据写出到文件中。
  5. 1.构造方法: ObjectOutputStream(OutputStream out)
  6. 2.序列化对象(将对象持久化保存): writeObject(Object obj)
  7. 3.要求:对象所属的类要实现 Serializable接口
  8. 4.transient关键字:被修饰的成员变量不会被序列化
  9. 目标:使用对象输入流将文件中的对象读入程序中
  10. ObjectInputStream(对象输入流/反序列化流)
  11. 把写到本地文件中的对象读到内存中。
  12. 1.构造方法: ObjectInputStream(InputStream in)
  13. 2.反序列化(将对象读回内存): Object readObject()
  14. */
  15. public static void main(String[] args) throws Exception {
  16. Person person = new Person("张三", 23);
  17. //创建对象输出流
  18. ObjectOutputStream output = new ObjectOutputStream(
  19. new FileOutputStream("Day11BufferedIO\\A\\c.txt")
  20. );
  21. //序列化对象(将对象持久化保存)
  22. output.writeObject(person);
  23. output.close();
  24. //创建对象输入流
  25. ObjectInputStream stream = new ObjectInputStream(
  26. new FileInputStream("Day11BufferedIO\\A\\c.txt")
  27. );
  28. //反序列对象(将对象读回内存)
  29. Object o = stream.readObject();
  30. System.out.println(o);
  31. stream.close();
  32. }
  33. //需要序列化对象,类要实现Serializable接口
  34. public class Person implements Serializable {
  35. //为当前类加一个唯一序列化标记
  36. private static final long serialVersionUID = 3725032426848681276L;
  37. private String name;
  38. //transient不让成员变量序列化
  39. private transient int age;
  40. //构造方法setgettoString
  41. }
  1. /*
  2. 目标:了解打印流的使用
  3. 1.打印流分类:
  4. 字节打印流: PrintStream
  5. 字符打印流: PrintWriter
  6. 2.PrintStream构造方法:
  7. PrintStream(String fileName) :根据字符串路径指定打印目的地。
  8. 3.重要方法:
  9. print(任意类型数据) 打印数据,不换行
  10. println(任意类型数据) 打印数据,换行
  11. 原样输出,参数写什么就打印什么
  12. 说明:PrintWriter和PrintStream用法几乎一样。
  13. 只不过PrintStream是操作字节,PrintWriter是操作字符。
  14. */
  15. public static void main(String[] args) throws Exception {
  16. //打印流
  17. PrintStream stream = new PrintStream("Day11BufferedIO\\A\\d.txt");
  18. //保存数据到文件并且换行
  19. stream.println("123");
  20. stream.print("qwe");
  21. stream.close();
  22. }
  1. /*
  2. 目标:掌握Properties保存和加载文件的方式
  3. 1.将Properties中的键值对数据保存到文件中:
  4. void store(Writer writer, String comments) :
  5. 第一个参数为字符输出流,第二个参数为写到文件的注释。
  6. */
  7. public static void main(String[] args) throws Exception {
  8. Properties p = new Properties();
  9. //添加键值对
  10. p.setProperty("张三", "23");
  11. p.setProperty("李四", "24");
  12. p.setProperty("王五", "25");
  13. p.store(new FileWriter("Day11BufferedIO\\A\\用户列表.txt"), "");
  14. }
  1. /*
  2. 2.加载文件数据到Properties集合中:
  3. void load (Reader reader) : 参数为字符输入流
  4. */
  5. public static void main(String[] args) throws Exception {
  6. Properties p = new Properties();
  7. p.load(new FileReader("Day11BufferedIO\\A\\用户列表.txt"));
  8. Set<String> keys = p.stringPropertyNames();
  9. for (String key : keys) {
  10. String s = p.getProperty(key);
  11. System.out.println(key + " = " + s);
  12. }
  13. }
  1. /*
  2. Properties作为Map集合的特有方法:
  3. Object setProperty(String key, String value) :添加键值对,键和值都是字符串类型。
  4. String getProperty(String key) :通过键获取值,获取不到返回null
  5. stringPropertyNames() 获取所有的属性名,遍历属性名获取属性值
  6. */
  7. public static void main(String[] args) {
  8. Properties p = new Properties();
  9. //setProperty 添加键值对,键和值都是字符串类型。
  10. p.setProperty("name","张三");
  11. p.setProperty("age","18");
  12. p.setProperty("address","广州");
  13. //getProperty(String key)
  14. String name = p.getProperty("name");
  15. System.out.println(name);
  16. //遍历 stringPropertyNames 获取所有的属性名
  17. Set<String> keys = p.stringPropertyNames();
  18. for (String key : keys) {
  19. String value = p.getProperty(key);
  20. System.out.println(key+","+value);
  21. }
  22. }