io流复习+代码演示

前置知识:

 序列化和反序列化

  1.序列化就是在保存数据时, 保存数据的值和数据类型
  2.反序列化就是在恢复数据时, 恢复数据的值和数据类型
  3.需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该
     类必须实现如下两个接口之一:
     Serializable //这是一个标记接口,没有方法
     Externalizable //该接口有方法需要实现,因此我们一般实现上面的Serializable接口

 

 IO流的三种分类

  第一种:输入流和输出流
    按照流的流向来分,可以分为输入流和输出流。输入,输出都是从程序运行所在内存的角度来划分的。
    输入流:只能从中读取数据,而不能向其写入数据,由InputStream和Reader作为基类。
    输出流:只能向其写入数据,而不能从中读取数据。由OutputStream和Writer作为基类

  第二种:字节流和字符流
    字节流和字符流的用法几乎完全一样,区别在于字节流和字符流所操作的数据单元不同。
    字节流操作的数据单元是8位字节,由InputStream和OutputStream作为基类。
    字符流操作的数据单元是16位的字符,由Reader和Writer作为基类

  第三种:节点流和处理流
    按照流的角色来分,可以分为节点流和处理流。
    节点流:可以从向一个特定的IO设备(如磁盘、网络)读/写数据的流。也被称为低级流。
    处理流:用于对一个已存在的流进行连接或封装,通过封装后的流来实现数据读/写功能。也称为高级流

           节点流和处理流的区别和联系
   1.节点流是底层流/低级流,直接跟数据源相接。
   2.处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。
   3.处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连[模拟修饰器设计模式]
    

   处理流的功能主要体现在以下两个方面:
   1.性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
   2.操作的便捷:处理流可能提供了- -系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便

   常见的处理流BufferedReader和BufferedWriter

   在关闭处理流时,只关闭外层流即可

一、字节流

字节流通常用来处理二进制文件,视频,音频,图片  

1、inputStream

  1.1、FileInputStream

/**
 * FileInputStream使用(文件-->程序)
 */
public class FileInputStream_ {
    public static void main(String[] args) {
      //  readFile01();
        readFile02();
    }

    //单个字节的读取,效率比较低
   public static void readFile01(){
        String filePath="D://a.txt";
       int readData=0;
       FileInputStream fileInputStream=null;
       try {
           //创建FileInputStream对象,用于读取 文件
           fileInputStream = new FileInputStream(filePath);
           //一个字节一个字节的读,读取的数据存储在readData里,如果返回-1,则代表读取完毕
           while ((readData = fileInputStream.read())!=-1){
               System.out.print((char) readData);//转成char输出
           }
       } catch (IOException e) {
           e.printStackTrace();
       }finally {
           //关闭文件流释放资源
           try {
               fileInputStream.close();
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
   }

    public static void readFile02(){
        String filePath="D://a.txt";
        int readLen=0;
        FileInputStream fileInputStream=null;
        //添加一个Byte容量设置为10数组
        byte[] bytes = new byte[9];
        try {
            //创建FileInputStream对象,用于读取文件
            fileInputStream = new FileInputStream(filePath);
            //从该输入流读取最多10个字节的数据到字节数组。
            //如果返回-1,则代表读取完毕
            //如果读取正常返回实际读取的字节数
            while ((readLen=fileInputStream.read(bytes))!=-1){
                System.out.print(new String(bytes,0,readLen));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭文件流释放资源
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

   1.2、ObjectInputStream(对象反序列化)

    注意先进行 ObjectOutputStream 序列化到 D:\a.dat 文件中 然后才进行的反序列化

public class ObjectInputStream_ {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //指定反序列化的文件
        String filePath="D:\\a.dat";

        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filePath));

        //读取
        //反序列的顺序需要和保存的数据的顺序一致,否则会出现异常
        System.out.println(objectInputStream.readInt());
        System.out.println(objectInputStream.readBoolean());
        System.out.println(objectInputStream.readChar());
        System.out.println(objectInputStream.readDouble());
        System.out.println(objectInputStream.readUTF());
        Object dog = objectInputStream.readObject();
        System.out.println("运行类型:"+dog.getClass());
        System.out.println("dog信息:"+dog);//底层 Object-->Dog

        //关闭外层流即可
        objectInputStream.close();
    }
}

可以看到输出:

2、OutputStream

  2.1、FileOutputStream

public class FileOutputStream_ {
    public static void main(String[] args) {
            writeFile();
    }
    /**
     * 使用FileOutputStream将数据写入文件中
     * 如果数据不存在,则自动创建该文件
     */
    public static void writeFile(){
        String filePath="D:\\a.txt";
        FileOutputStream fileOutputStream=null;
        try {
            //得到FileOutputStream对象
            //1、这种创建方式,写入的内容是覆盖原来的文件中的内容
            //2、在构造器中添加 true 为追加填写
            fileOutputStream = new FileOutputStream(filePath,true);

            //写入一个字节
            // fileOutputStream.write('a');   fileOutputStream.write(97);

            //写入字符串   str.getBytes()字符串转为字节数组
            String str="hollow";
            //fileOutputStream.write(str.getBytes());

            //也可以指定字节数组中的起始位置,末尾位置
            fileOutputStream.write(str.getBytes(),0,str.length());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

   2.2、ObjectOutputStream(对象序列化)  

/**
 * ObjectOutputStream的使用,完成数据的序列化
 */
public class ObjectOutputStream_ {
    public static void main(String[] args) throws Exception {
        //序列化后,保存的格式,不是纯文本,而是按照他的格式来保存
        String filePath = "D:\\a.dat";
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));

        //序列化数据到 D:\a.bat
        objectOutputStream.write(100);//int-->Integer(实现了Serializable)
        objectOutputStream.writeBoolean(true);//boolean-->Boolean(实现了Serializable)
        objectOutputStream.writeChar('a');//chat-->Character(实现了Serializable)
        objectOutputStream.writeDouble(1.1);//double-->Double(实现了Serializable)
        objectOutputStream.writeUTF("阿龙学习");//String

        //保存一个对象
        objectOutputStream.writeObject(new Dog("旺财",5));
        objectOutputStream.close();
        System.out.println("序列化数据保存完毕");
    }
}
//lombok插件
@Data
@AllArgsConstructor
@NoArgsConstructor
//要实现Serializable接口才能够进行序列化
class Dog implements Serializable {
    private String name;
    private int age;
}

   2.3、PrintStream(字节打印流)  

/**
 * PrintStream字节打印流
 */
public class PrintStream_ {
    public static void main(String[] args) throws IOException {
        // System.out 就是 PrintStream
        PrintStream out = System.out;
        //在默认情况下,默认打印的是标准输出(即 显示器)
        out.println("你好");
        //因为底层使用的是write,所以可以直接调用write进行打印/输出
        out.write("hello,你好!".getBytes(StandardCharsets.UTF_8));
        //关闭流。
        out.close();
        //我们可以修改打印输出流的位置/设备
        //修改成"D:\\a.txt"
        //这句话将会输出到D:\a.txt
        System.setOut(new PrintStream("D:\\a.txt"));
        System.out.println("这句话将会输出到D:\\a.txt");
    }
}

 

二、字符流

  通常用来处理文本文件,更高效。

1、Reader

   1.1、FileReader 

public class FileReader_ {
    public static void main(String[] args) {
        String filePath="d:\\a.txt";
        FileReader fileReader=null;
        int data= 0;
        char[] chars = new char[10];
        //1、创建FileReader对象
        try {
            fileReader = new FileReader(filePath);
            //循环读取,使用read(chars),返回的是实际读取到的字符数
            //如果返回-1则表示读到文件结尾
           while ((data = fileReader.read(chars))!=-1){
               System.out.print(new String(chars,0,data));
           }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fileReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  1.2、BufferedReader         

    BufferedReader类中,有属性Reader,即可以封装一个节点流,该节点流可以是任意的,只要是Reader子类 (BufferedWriter也是一样的操作)

    

public class BufferedReader_ {
    public static void main(String[] args) throws Exception {  //异常也可以try catch
        String filePath = "D:\\a.txt";

        //创建bufferedReader
        BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
        //读取
        String line;//按行读取,效率高
        //1.bufferedReader.readLine() 按行读取文件
        //2.当返回为空时,表示文件读取完毕。
         while ((line = bufferedReader.readLine())!=null){
             System.out.println(line);
         }
         //关闭流,只需要关闭外层的流,即bufferedReader,因为底层会自动的去关闭节点流 FileReader
         bufferedReader.close();
    }
}

  1.3、InputStreamReader(转换流,并可以指定编码格式读取)

/**
 * InputStreamReader  转换流解决中文乱码问题
 * 将字节流 FileInputStream 转换成字符流 InputStreamReader, 指定编码 gbk/utf-8
 */
public class InputStreamReader_ {
    public static void main(String[] args) throws IOException {
        String filePath = "D:\\a.txt";
        //把 new FileInputStream(filePath) 转成 InputStreamReader 同时指定了编码 utf-8
        InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath), StandardCharsets.UTF_8);
        //把 InputStreamReader 传入 BufferedReader
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        String readLine;
        while(( readLine = bufferedReader.readLine())!=null){
            System.out.println(readLine);
        }
        bufferedReader.close();
    }
}

2、Writer

  2.1、FileWriter

             注意:FileWriter使用后,必须要关闭(close)或刷新(flush)流, 否则写入不到指定的文件!

public class FileWriter_ {
    public static void main(String[] args) {
        String filePath="D:\\a.txt";
        FileWriter fileWriter=null;
        String str="哈哈哈哈哈哈哈哈哈";
        try {
            fileWriter = new FileWriter(filePath,true);//true为追加,不写则覆盖
            //fileWriter.write(str);
            fileWriter.write(str,0,2);//指定str的某一部分
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  2.2、BufferedWriter

public class BufferedWriter_ {
    public static void main(String[] args) throws IOException {
        String filePath="D:\\a.txt";
        //创建BufferedWriter
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));//追加要在节点流中进行设置
        bufferedWriter.write("红红火火恍恍惚惚红红火火恍恍惚惚吼吼吼1");
        //插入一个换行
        bufferedWriter.newLine();
        bufferedWriter.write("红红火火恍恍惚惚红红火火恍恍惚惚吼吼吼2");
        //插入一个换行
        bufferedWriter.newLine();
        bufferedWriter.write("红红火火恍恍惚惚红红火火恍恍惚惚吼吼吼3");

        //关闭外层流即可
        bufferedWriter.close();
    }

}

  2.3、OutputStreamWriter(转换流,并可以指定编码格式写入)

/**
 * 将字节流FileOutputStream包装成(转换成)字符流OutputStreamWriter,
 * 对文件进行写入(按照gbk格式,可以指定其他,比如utf-8/utf8)
 */
public class InputStreamWriter_ {
    public static void main(String[] args) throws IOException {//异常直接进行的抛出,也可以try catch
        String filePath = "D:\\a.txt";
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(filePath), "gbk");
        outputStreamWriter.write("gbk格式的编码");
        //关闭流
        outputStreamWriter.close();
    }
}

  2.4、PrintWriter(字符打印流)

public class PrintWriter_ {
    public static void main(String[] args) throws IOException {
        //创建PrintWriter对象
        PrintWriter printWriter = new PrintWriter(new FileWriter("D:\\a.txt"));
        //将会打印到 D:\a.txt
        printWriter.println("哈喽你好 ");
        printWriter.close(); //flush + 关闭流
    }
}

 

三、Properties类 

  load:加载配置文件的键值对到Properties对象
  list:将数据显示到指定设备
  getProperty(key):根据键获取值
  setProperty(key,value):设置键值对到Properties对象
  store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果
  含有中文,会存储为unicode码

  1、Properties读取数据   

public class Properties_read {
    public static void main(String[] args) throws IOException {
        //使用Properties读取ycl.properties文件
        Properties properties = new Properties();
        //加载指定的配置文件
        properties.load(new FileReader("src/main/resources/ycl.properties"));
        //键值对显示到控制台
        properties.list(System.out);
        //根据key 获取对应的值
        String id = properties.getProperty("id");
        System.out.println("id是:"+id);
    }
}

  2、Properties写入数据

public class Properties_writer {
    public static void main(String[] args) throws IOException {
        //使用Properties类, 创建配置文件,修改配置文件内容
        Properties properties = new Properties();

        //设置内容
     //如果该文件没有对应的key,就是创建
     //如果该文件有对应的key,就是修改 properties.setProperty("charset","utf-8"); properties.setProperty("username","小刚");//中文保存的是unicode码 properties.setProperty("pwd","123567894"); //将k-v 存储至文件 properties.store(new FileOutputStream("D:\\a.data"),null); System.out.println("保存成功"); } }

 

  

 

四、copy练习

  1、字节流copy练习

 

public class FileCopy {
    public static void main(String[] args) {
            copy();
    }
    public static void copy(){
        String resourcePath="D:\\壁纸\\1.jpg";
        String targetPath="D:\\壁纸\\3.jpg";
        FileInputStream fileInputStream=null;
        FileOutputStream fileOutputStream=null;
        int readLen=0;
        try {
            fileInputStream = new FileInputStream(resourcePath);
            fileOutputStream=new FileOutputStream(targetPath);
            //定义一个数组提高效率
            byte[] bytes = new byte[1024];
            while ((readLen=fileInputStream.read(bytes))!=-1){
                //边读边写
                fileOutputStream.write(bytes,0,readLen);//必须用这个参数,否则出现文件损失
            }
            System.out.println("copy完成");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fileInputStream.close();
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

   2、缓冲字符流copy文本练习

    BufferedReader和BufferedWriter 是按照字符操作的,不要去操作二进制文件(声音、视频、doc、pdf、图片等等),拷贝后的文件可能会造成文件损坏

public class Buffered_copy {
    public static void main(String[] args) {
        //源文件路径
        String resourcePath = "D:\\a.txt";
        //目标文件的路径
        String targetPath = "D:\\b.txt";
        BufferedReader bufferedReader = null;
        BufferedWriter bufferedWriter = null;
        try {
            //创建bufferedReader、bufferedWriter
            bufferedReader = new BufferedReader(new FileReader(resourcePath));
            bufferedWriter = new BufferedWriter(new FileWriter(targetPath,true));//true表示追加写入
            String line;
            //readLine() 读取一行内容,但是没有换行
            while ((line = bufferedReader.readLine()) != null) {
                //每读取一行就写入
                bufferedWriter.write(line);
                //插入换行
                bufferedWriter.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                //关闭流
                if (bufferedReader!=null){
                    bufferedReader.close();
                }
                if (bufferedWriter!=null){
                    bufferedWriter.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

   3、缓冲字节流copy二进制文件(copy文本文件一样可以) 

/**
 * BufferedInputStream、BufferedOutputStream的使用
 */
public class Buffered_copy02 {
    public static void main(String[] args) {
        String resourcePath = "D:\\壁纸\\2.jpg";
        String targetPath = "D:\\壁纸\\4.jpg";
        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;
        try {
            //创建对象
            bufferedInputStream = new BufferedInputStream(new FileInputStream(resourcePath));
            bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(targetPath));
            int readLen;
            byte[] buf = new byte[1024];
            //返回读取到的长度,当返回-1时,就表示文件读取完毕
            while ((readLen = bufferedInputStream.read(buf))!=-1){
                bufferedOutputStream.write(buf,0,readLen);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                //关闭外层处理流即可,底层会自动关闭节点流
                if (bufferedInputStream != null) {
                    bufferedInputStream.close();
                }
                if (bufferedOutputStream!=null){
                    bufferedOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 

   

posted @ 2022-01-29 20:23  along-Blog  阅读(194)  评论(0编辑  收藏  举报