• Java回顾-IO流-节点流/缓冲流/对象流/转换流


    一、节点流(文件流)

            1. 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
            2. 对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,...),使用字节流处理

    1.FileWriter& FileReader

            读取:

    1. File file=new File("hello.txt");
    2. FileReader fr=new FileReader(file);
    3. //1.空参构造器
    4. int data = fr.read();//返回读入的一个字符,到末尾返回-1
    5. while (data!=-1){
    6. System.out.print((char)data);
    7. data= fr.read();
    8. }
    9. //2.char[]参数
    10. char[] cbuffer=new char[5];
    11. int len;//记录字符个数
    12. while ((len= fr.read(cbuffer))!=-1){
    13. for(int i=0;i<len;i++) System.out.print(cbuffer[i];
    14. }
    15. fr.close();

            复制: 

    1. //复制文件
    2. File file=new File("hello.txt");
    3. FileReader fr=new FileReader(file);
    4. //若文件不存在,则创建新文件;文件存在的话可以设置 append参数 选择覆盖还是追加
    5. File file1=new File("hello1.txt");
    6. FileWriter fw=new FileWriter(file1,false);
    7. char[] cbuffer=new char[5];
    8. int len;//记录字符个数
    9. while ((len= fr.read(cbuffer))!=-1){
    10. fw.write(cbuffer,0,len);
    11. }
    12. fr.close();
    13. fw.close();

            注:FileWriter的第二个参数可设置是覆盖还是追加

    2. FileInputStream& FileoutputStream

       实现对图片的复制操作:

    1. @Test
    2. public void testFileInputOutputStream() {
    3. FileInputStream fis = null;
    4. FileOutputStream fos = null;
    5. File srcFile = new File("test.jpg");
    6. File destFile = new File("test1.jpg");
    7. fis = new FileInputStream(srcFile);
    8. fos = new FileOutputStream(destFile);
    9. //复制的过程
    10. byte[] buffer = new byte[5];
    11. int len;
    12. while((len = fis.read(buffer)) != -1){
    13. fos.write(buffer,0,len);
    14. }
    15. fos.close();
    16. fis.close();
    17. }

    二、缓冲流

            为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类 时,会创建一个内部缓冲区数组,缺省使用8192个字节(8Kb)的缓冲区 

            缓冲流要“套接”在相应的节点流之上,根据数据操作单位可以把缓冲流分为: 

                     -BufferedInputStream

                     -BufferedOutputStream

                     -BufferedReader

                     -BufferedWriter

            当读取数据时,数据按块读入缓冲区,其后的读操作则直接访问缓冲区

            当使用BufferedInputStream读取字节文件时,会一次性从文件中读取8192个(8Kb),存在缓冲区中,直到缓冲区装满了,才重新从文件中读取下一个8192个字节数组。

            向流中写入字节时,不会直接写到文件,先写到缓冲区中直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。使用方法 flush()可以强制将缓冲区的内容全部写入输出流

            关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可,关闭最外层流也会相应关闭内层节点流

    1. BufferedInputStream & BufferedOutputStream

    1. /*
    2. 实现非文本文件的复制
    3. */
    4. @Test
    5. public void BufferedStreamTest(){
    6. BufferedInputStream bis = null;
    7. BufferedOutputStream bos = null;
    8. //1.造文件
    9. File srcFile = new File("爱情与友情.jpg");
    10. File destFile = new File("爱情与友情3.jpg");
    11. //2.造流
    12. //2.1 造节点流
    13. FileInputStream fis = new FileInputStream((srcFile));
    14. FileOutputStream fos = new FileOutputStream(destFile);
    15. //2.2 造缓冲流
    16. bis = new BufferedInputStream(fis);
    17. bos = new BufferedOutputStream(fos);
    18. //3.复制的细节:读取、写入
    19. byte[] buffer = new byte[10];
    20. int len;
    21. while((len = bis.read(buffer)) != -1){
    22. bos.write(buffer,0,len);
    23. //4.资源关闭
    24. //要求:先关闭外层的流,再关闭内层的流
    25. bos.close();
    26. bis.close();
    27. //说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略.
    28. }

    2.BufferedReader & BufferedWriter

    1. /*
    2. 使用BufferedReader和BufferedWriter实现文本文件的复制
    3. */
    4. @Test
    5. public void testBufferedReaderBufferedWriter(){
    6. BufferedReader br = null;
    7. BufferedWriter bw = null;
    8. //创建文件和相应的流
    9. br = new BufferedReader(new FileReader(new File("dbcp.txt")));
    10. bw = new BufferedWriter(new FileWriter(new File("dbcp1.txt")));
    11. //读写操作
    12. //方式一:使用char[]数组
    13. char[] cbuf = new char[1024];
    14. int len;
    15. while((len = br.read(cbuf)) != -1){
    16. bw.write(cbuf,0,len);
    17. bw.flush();
    18. }
    19. //方式二:使用String,每次读一行数据
    20. String data;
    21. while((data = br.readLine()) != null){
    22. //方法一:
    23. bw.write(data + "\n");//data中不包含换行符
    24. //方法二:
    25. bw.write(data);//data中不包含换行符
    26. bw.newLine();//提供换行的操作
    27. }
    28. //关闭资源
    29. if(bw != null){
    30. bw.close();
    31. br.close();
    32. }

            注:BufferedReader有一个额外的方法 readLine(),可以读一行的字符。

    三、对象流 

             用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

            序列化:用ObjectOutputStream保存基本类型数据或对象的机制

            反序列化:用ObjectInputStream读取基本类型数据或对象的机制

            ObjectOutputStream和 ObjectInputStream不能序列化statictransient修饰的成员变量

    1.序列化

            对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从 而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象

            如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,为了让某个类是可序列化的,该类必须实现Serializable接口

            凡是实现Serializable接口的类都有一个表示序列化版本标识符静态变量

            private static final long serialVersionUID;

            serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容。

            如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议, 显式声明。

    2.序列化过程

            若某个类实现了 Serializable 接口,该类的对象就是可序列化的:

                    1.创建一个 ObjectOutputStream

                    2.调用 ObjectOutputStream 对象的 writeObject(对象) 方法输出可序列化对象

                    3.注意写出一次,操作flush()一次

            反序列化

                    1.创建一个 ObjectInputStream

                    2.调用 readObject() 方法读取流中的对象

            强调:如果某个类的属性不是基本数据类型String 类型,而是另一个引用类型,那么这个引用类型必须是可序列化的,否则拥有该类型的 Field 不能序列化 。

    1. /**
    2. * 对象流的使用
    3. */
    4. public class ObjectInputOutputStreamTest {
    5. /*
    6. 序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
    7. 使用ObjectOutputStream实现
    8. */
    9. @Test
    10. public void testObjectOutputStream(){
    11. //1.
    12. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
    13. //2.
    14. oos.writeObject(new String("我爱北京天安门"));
    15. oos.flush();//刷新操作
    16. oos.writeObject(new Person("王铭",23));
    17. oos.flush();
    18. oos.writeObject(new Person("张学良",23,1001,new Account(5000)));
    19. oos.flush();
    20. //3.
    21. oos.close();
    22. }
    23. /*
    24. 反序列化:将磁盘文件中的对象还原为内存中的一个java对象
    25. 使用ObjectInputStream来实现
    26. */
    27. @Test
    28. public void testObjectInputStream(){
    29. ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.dat"));
    30. Object obj = ois.readObject();
    31. String str = (String) obj;
    32. Person p = (Person) ois.readObject();
    33. Person p1 = (Person) ois.readObject();
    34. System.out.println(str);
    35. System.out.println(p);
    36. System.out.println(p1);
    37. ois.close();
    38. }
    39. import java.io.Serializable;
    40. /**
    41. * Person需要满足如下的要求,方可序列化
    42. * 1.需要实现接口:Serializable
    43. * 2.当前类提供一个全局常量:serialVersionUID
    44. * 3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性
    45. * 也必须是可序列化的。(默认情况下,基本数据类型可序列化)
    46. *
    47. * 补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
    48. */
    49. public class Person implements Serializable{
    50. public static final long serialVersionUID = 475463534532L;
    51. private String name;
    52. private int age;
    53. private int id;
    54. private Account acct;
    55. public Person(String name, int age, int id) {
    56. this.name = name;
    57. this.age = age;
    58. this.id = id;
    59. }
    60. public Person(String name, int age, int id, Account acct) {
    61. this.name = name;
    62. this.age = age;
    63. this.id = id;
    64. this.acct = acct;
    65. }
    66. @Override
    67. public String toString() {
    68. return "Person{" +
    69. "name='" + name + '\'' +
    70. ", age=" + age +
    71. ", id=" + id +
    72. ", acct=" + acct +
    73. '}';
    74. }
    75. public int getId() {
    76. return id;
    77. }
    78. public void setId(int id) {
    79. this.id = id;
    80. }
    81. public String getName() {
    82. return name;
    83. }
    84. public void setName(String name) {
    85. this.name = name;
    86. }
    87. public int getAge() {
    88. return age;
    89. }
    90. public void setAge(int age) {
    91. this.age = age;
    92. }
    93. public Person(String name, int age) {
    94. this.name = name;
    95. this.age = age;
    96. }
    97. public Person() {
    98. }
    99. }
    100. class Account implements Serializable{
    101. public static final long serialVersionUID = 4754534532L;
    102. private double balance;
    103. @Override
    104. public String toString() {
    105. return "Account{" +
    106. "balance=" + balance +
    107. '}';
    108. }
    109. public double getBalance() {
    110. return balance;
    111. }
    112. public void setBalance(double balance) {
    113. this.balance = balance;
    114. }
    115. public Account(double balance) {
    116. this.balance = balance;
    117. }
    118. }

    四、转换流

            转换流提供了在字节流和字符流之间的转换,很多时候我们使用转换流来处理文件乱码问题,实现编码和解码的功能。

    InputStreamReader

            实现将字节输入流按指定字符集转换为字符输入流

            需要和InputStream“套接”。

             public InputStreamReader(InputStream in)

             public InputSreamReader(InputStream in,String charsetName)

    OutputStreamWriter

            实现将字符输出流按指定字符集转换为字节输出流

            需要和OutputStream“套接”。

            public OutputStreamWriter(OutputStream out)

            public OutputSreamWriter(OutputStream out,String charsetName)

    1. //解码:字节、字节数组 --->字符数组、字符串
    2. //编码:字符数组、字符串 ---> 字节、字节数组
    3. /*
    4. InputStreamReader的使用,实现字节的输入流到字符的输入流的转换
    5. */
    6. @Test
    7. public void test1() {
    8. FileInputStream fis = new FileInputStream("dbcp.txt");
    9. //参数2指明了字符集,具体使用哪个字符集,取决于文件dbcp.txt保存时使用的字符集
    10. InputStreamReader isr = new InputStreamReader(fis,"UTF-8");//使用系统默认的字符集
    11. char[] cbuf = new char[20];
    12. int len;
    13. while((len = isr.read(cbuf)) != -1){
    14. String str = new String(cbuf,0,len);
    15. System.out.print(str);
    16. }
    17. isr.close();
    18. }
    19. /*
    20. 综合使用InputStreamReader和OutputStreamWriter
    21. */
    22. @Test
    23. public void test2() {
    24. //1.造文件、造流
    25. File file1 = new File("dbcp.txt");
    26. File file2 = new File("dbcp_gbk.txt");
    27. FileInputStream fis = new FileInputStream(file1);
    28. FileOutputStream fos = new FileOutputStream(file2);
    29. InputStreamReader isr = new InputStreamReader(fis,"utf-8");
    30. OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
    31. //2.读写过程
    32. char[] cbuf = new char[20];
    33. int len;
    34. while((len = isr.read(cbuf)) != -1){
    35. osw.write(cbuf,0,len);
    36. }
    37. //3.关闭资源
    38. isr.close();
    39. osw.close();
    40. }

  • 相关阅读:
    国庆day1
    Windows AD共享权限管理工具
    SegNeXt学习记录(一):配置环境 & 测试代码
    Git源码阅读笔记
    Web3:Fediverse低效是一种平衡 - berk
    Echarts的配置修改
    风靡全国的真人猫抓老鼠是什么?
    【Django】开发日报_1.1_Day:模板语法
    前端实战|React18极客园——登陆模块(token持久化、路由拦截、mobx、封装axios)
    NCP81239MNTXG 开关降压/升压控制器,USB 功率传递和 Type-C 应用
  • 原文地址:https://blog.csdn.net/weixin_62427168/article/details/125477293