美文网首页Android基础Java 基础
Java 基础 07. Java I/O 流

Java 基础 07. Java I/O 流

作者: yjtuuige | 来源:发表于2021-12-25 18:20 被阅读0次

    1. 流的概念

    • 内存与存储设备之间传输数据的通道
    • 数据借助流传输

    2. 流的分类

    按方向(重点)

    • 输入流:将 存储设备 中的内容读到 内存 中;
    • 输出流:将 内存 中的内容写到 存储设备 中;

    按单位

    • 字节流:以字节为单位,可以读写 所有数据
    • 字符流:以字符为单位,只能读写 文本数据

    按功能

    • 节点流:具有 实际传输数据读写功能
    • 过滤流:在节点流的基础之上 增强功能

    3. 字节流

    • 字节流的父类(抽象类)
    // InputStream 字节输入流 (读取)
    public int read(){}
    public int read(byte[] b){}
    public int read(byte[] b, int off, int len){}
    
    // OutputStream 字节输出流 (写入)
    public void write(int n){}
    public void write(byte[] b){}
    public void write(byte[] b, int off, int len){}
    

    文件字节流

    • 文件字节输入流:FileInputStream
    public static void main(String[] args) throws Exception{
      // 1 创建FileInputStream 并指定文件路径
      FileInputStream fis = new FileInputStream("d:\\abc.txt");
      // 2 读取文件
      // fis.read();
      // 2.1单字节读取
      int data = 0;
      while((data = fis.read()) != -1){
        System.out.println((char)data);
      }
      // 2.2 一次读取多个字节
      byte[] buf = new byte[3]; // 大小为3的缓存区
      int count = fis.read(buf); // 一次读3个
      System.out.println(new String(buf));
      System.out.println(count);
      int count2 = fis.read(buf); // 再读3个
      System.out.println(new String(buf));
      System.out.println(count2);
      
      // 上述优化后
      int count = 0;
      while((count = fis.read(buf)) != -1){
        System.out.println(new String(buf, 0, count));
      }
      
      // 3 关闭
      fis.close();
    }
    
    • 文件字节输出流:FileOutputStream
    public static void main(String[] args) throws Exception{
      // 1 创建文件字节输出流
      // true 表示不覆盖 接着写 
      FileOutputStream fos = new FileOutputStream("路径", true);
        // 2 写入文件
      fos.write(97);
      fos.write('a');
      // String string = "hello world";
      fos.write(string.getBytes());
      // 3 关闭
      fos.close();
    } 
    

    图片复制案例

    // 1 创建流
    // 1.1 文件字节输入流
    FileInputStream fis = new FileInputStream("路径");
    // 1.2 文件字节输出流
    FileInputStream fos = new FileOutpuStream("路径");
    // 2 边读边写
    byte[] buf = new byte[1024];
    int count = 0;  // 计数器
    while((count = fis.read(buf)) != -1){
      fos.write(buf, 0, count);
    }
    // 3 关闭
    fis.close();
    fos.close();
    

    字节缓冲流(过滤流):提高 IO 效率

    • 缓冲流:BufferedInputStream/ BufferedOutputStream
      • 提高 IO 效率,减少访问磁盘次数;
      • 数据存储在缓冲区中(8K),flush 是将缓冲区的内容写入文件中,也可以直接 close。
    • BufferedInputStream:读取文件
    // 使用字节缓冲流 读取 文件
    public static void main(String[] args) throws Exception{  // 抛出异常
      // 1 创建BufferedInputStream
      FileInputStream fis = new FileInputStream("路径");
      BufferedInputStream bis = new BufferedInputStream(fis);
      // 2 读取  BufferedInputStream内部自定义了8K缓冲区
      int data = 0;
      while((data = bis.read()) != -1){
        System.out.print((char)data);
      }
      // 用自己创建的缓冲流
      byte[] buf = new byte[1024];
      int count = 0;
      while((count = bis.read(buf)) != -1){
        System.out.println(new String(buf, 0, count));
      }
      
      // 3 关闭,同时也关闭了 fis
      bis.close();
    }
    
    • BufferedOutputStream:写入文件
    // 使用字节缓冲流 写入 文件
    public static void main(String[] args) throws Exception{
      // 1. 创建BufferedInputStream
      FileOutputStream fos = new FileOutputStream("路径");
      BufferedOutputStream bis = new BufferedOutputStream(fos);
      // 2. 写入文件
      for(int i = 0; i < 10; i ++){
        bos.write("hello".getBytes());// 写入内部 8k 缓冲区
        bos.flush(); // 刷新缓冲区,写入到硬盘
      }
      // 3. 关闭(内部调用flush())
      bos.close();
    }
    

    4. 对象流:ObjectOutputStream / ObjectInputStream

    • 增强了缓冲区功能
    • 增强了读写 8 种基本数据类型和字符串的功能
    • 增强了读写对象的功能
      • readObject(); :从流中读取一个对象(反序列化
      • writeObject(Object obj); :向流中写入一个对象(序列化
    • 使用流传输对象的过程,称为序列化、反序列化

    5. 序列化与反序列化

    序列化

    • 实例:创建 Student 类实现 Serializable 接口
    package com.base.demo06;
    
    import java.io.Serializable;
    
    // 要求:序列化类,必须要实现 Serializable 接口
    public class Student implements Serializable {
        // serialVersionUID 序列化版本号,保证序列化、反序列化为同一个类
        private static final long serialVersionUID = -3115151823789216775L;
        private String name;
        // transient(内存中,瞬时的) 不被序列化
        private transient int age;
        // 静态属性,不被序列化
        private static String country = "China";
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        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;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    • 序列化
    package com.base.demo06;
    
    import java.io.FileOutputStream;
    import java.io.ObjectOutputStream;
    import java.util.ArrayList;
    
    public class Demo06 {
        public static void main(String[] args) throws Exception {
            /*
            1. 使用 ObjectOutputStream 实现对象的序列化(写入)
            2. 要求:序列化类,必须要实现 Serializable 接口
            */
            // 1. 创建对象流
            FileOutputStream fos = new FileOutputStream("d:\\stu.bin");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            // 2. 序列化(写入操作)
            Student s1 = new Student("Liu", 20);
            // 创建多个对象
            Student s2 = new Student("Chen", 21);
            // 集合方式
            ArrayList<Student> list = new ArrayList<>();
            list.add(s1);
            list.add(s2);
    
            /*
            普通方式,写入多个对象
            oos.writeObject(s1);
            oos.writeObject(s2);
            */
    
            // 集合写入
            oos.writeObject(list);
    
            // 3. 关闭
            oos.close();
            System.out.println("序列化完华");
        }
    }
    

    反序列化

    • 实例:
    package com.base.demo06;
    
    import java.io.FileInputStream;
    import java.io.ObjectInputStream;
    import java.util.ArrayList;
    
    public class Demo07 {
        public static void main(String[] args) throws Exception {
            // 使用 ObjectInputStream 实现反序列化(读取重构成对象)
            // 1.创建对象流
            FileInputStream fis = new FileInputStream("d:\\stu.bin");
            ObjectInputStream ois = new ObjectInputStream(fis);
    
            // 2.读取文件(反序列化)
    //        Student s = (Student) ois.readObject();    // 强制转换成 Student 类型
    //        Student s1 = (Student) ois.readObject();
            // 集合方式读取
            ArrayList<Student> list = (ArrayList<Student>) ois.readObject();    // 强制转换
            // 3.关闭
            ois.close();
            System.out.println("反序列化,执行完华");
    //        System.out.println(s.toString());
    //        System.out.println(s1.toString());
            System.out.println(list.toString());
        }
    }
    
    • 运行结果:
    • readObject(),读取完后,再次读取时,会出现异常

    注意事项:

    1. 类要想序列化,必须实现 Serializable 接口;
    2. 序列化类中,对象属性要求实现 Serializable 接口;
    3. 序列化版本号 ID(serialVersionUID),保证序列化的类和反序列化的类是同一个类;
    4. 使用 transient(内存中,瞬时的)修饰属性,这个属性就不能被序列化;
    5. 静态属性(static)不能被序列化;
    6. 序列化多个对象,可以借助集合来实现。

    6. 编码方式

    • UTF-8 等
      编码方式要一致:当编码方式和解码方式不一致时,会出现乱码。

    7. 字符流

    // 传统字节流读取
    public static void main(String[] args){
      // 1. 创建FileInputStream 对象
      FileInputSteam fis = new FileInputStream("路径");
      // 2. 读取
      int data = 0;
      // 3. 字节流按一个字节为单位来读取
      while((data = fis.read()) != -1){
        System.out.print((char)data); 
      }
      // 3. 关闭
      fis.close();
    }
    
    • 字节流读取汉字时乱码:(一般一个汉字 2 个字节),字节流按一个字节为单位读取

    字符流的父类(抽象类)

    • reader 字符输入流
      • public int read(){}
      • public int read(char[] c){}
      • public int read(char[] b, int off, int len){}
    • writer 字符输出流
      • public void write(int n){}
      • public void write(String str){}
      • public void write(char[] c){}

    FileReader 文件字符输入流:(读取)

    // 1. 创建FileReader 文件字符输入流
    FileReader fr = new FileReader("路径");
    // 2. 读取
    // 2.1 单个字符读取
    int data = 0;
    while((data = fr.read()) != -1){
      System.out.print((char)data);// 读取一个字符
    }
    // 2.2 字符缓冲区读取
    char[] buf = new char[2];
    int count = 0;  // 计数器
    while((count = fr.read(buf) != -1)){
      System.out.println(new String(buf, 0, count));
    }
    // 3. 关闭
    fr.close();
    

    FileWriter 文件字符输出流:(写入)

    // 1. 创建FileWriter对象
    FileWriter fw = new FileWriter("路径");
    // 2. 写入
    for(int i = 0; i < 10; i ++){
      fw.write("写入的内容\r\n");  // \r\n 换行
      fw.flush();  // 刷新,写入
    }
    // 3. 关闭
    fw.close();
    System.out.println("执行完毕");
    

    案例:文本文件复制

    • 字符流:不能复制图片或二进制文件;字节流:可以复制任意文件
      字符流读取文件时,会将文件转化成字符
    public static void main(String[] args) throws Exception{
      // 1. 创建流
      FileReader fr = new FileReader("路径");
      FileWriter fw = new FileWriter("路径");
      // 2. 读写
      int data = 0;
      while((data = fr.read()) != -1){
        fw.write(data);
        // 刷新,写入
        fw.flush();
      }
      // 3. 关闭
      fw.close();
      fr.close();
    }
    

    字符缓冲流:BufferedReader / BufferedWriter

    • 高效读写;
    • 支持输入换行符;
    • 可一次写一行读一行。

    BufferedReader:读取缓冲流

    public static void main(String[] args) throws Exception{
      // 创建缓冲流
      FileReader fr = new FileReader("路径");
      BufferedReader br = new BufferedReader(fr);
      // 读取
      // 1. 第一种方式
      char[] buf = new char[1024];  // 自定义缓冲区
      int count = 0;
      while((count = br.read(buf)) != -1){
        System.out.print(new String(buf, 0, count));
      }
      // 2. 第二种方式:readLine() 一行一行读取
      String line = null;
      while((line = br.readLine()) != null){
        System.out.println(line);
      }
      // 3.关闭
      br.close();
    }
    

    BufferedWriter:写入缓冲流

    public static void main(String[] args) throws Exception{
      // 1. 创建BufferedWriter对象
      FileWriter fw = new FileWriter("路径");
      BufferedWriter bw = new BufferedWriter(fw);
      // 2. 写入
      for(int i = 0; i < 10; i ++){
        bw.write("写入的内容");
        bw.newLine();  // 写入一个换行符,根据操作系统,自动调整
        bw.flush();
      }
      // 3. 关闭
      bw.close(); // 此时会自动关闭fw
    }
    

    PrintWrite:打印流

    • 封装了print() / println() 方法,支持写入后换行
    • 支持数据原样打印
    public static void main(String[] args) throws Exception{
      // 1 创建打印流
      PrintWriter pw = new PrintWriter("路径");
      // 2 打印
      pw.println(97);  // 97 原样打印,非字母 a
      pw.println(true);
      pw.println(3.14);
      pw.println('a');
      // 3 关闭
      pw.close();
    }
    

    转换流

    • 又称桥转换流: InputStreamReader / OutputStreamWriter
    • 可将字节流转换为字符流
    • 可设置字符的编码方式

    InputStreamReader:读取

    public static void main(String[] args) throws Exception{
      // 1 创建InputStreamReader对象
      FileInputStream fis = new FisInputStream("路径");
      // 指定读取编码方式,要与文件编码方式统一,否则乱码
      InputStreamReader isr = new InputStreamReader(fis, "utf-8");
      // 2 读取文件
      int data = 0;
      while((data = isr.read()) != -1){
        System.out.print((char)data);
      }
      // 3 关闭
      isr.close();
    }
    

    OutputStreamWriter:写入

    public static void main(String[] args) throws Exception{
      // 1 创建OutputStreamReader对象
      FileOutputStream fos = new FisOutputStream("路径");
      OutputStreamWriter osw = new OutputStreamReader(fos,"utf-8");
      // 2 写入
      for(int i = 0; i < 10; i ++){
        osw.write("写入内容\r\n");
        osw.flush();
      }
      // 3 关闭
      osw.close();
    }
    

    8. File 类

    概念:代表物理盘符中的一个 文件 或者 文件夹

    方法名 说明
    createNewFile() 创建一个新文件,需要声明异常
    mkdir() 创建一个新目录
    delete() 删除文件或空目录
    exists() 判断文件或目录是否存在
    getAbsolutePath() 获取文件的绝对路径
    getName() 获取文件或目录的名称
    getParent() 获取文件或目录所在的目录名称
    isDirectory() 判断是否是一个目录
    isFile() 判断是否是文件
    length() 获取文件的长度
    ListFiles() 列出目录中的所有内容
    renameTo() 修改文件名称
    • 分隔符、文件操作、文件夹操作
    /*
    File类的使用
    1. 分隔符
    2. 文件操作
    3. 文件夹操作
    */
    public class Demo01 {
        public static void main(String[] args) throws Exception {
            // 1.分隔符
            // separator();
            // 2.文件操作
            fileOpe();
            // 3.文件夹操作
            // directoryOpe();
        }
      // 1、分隔符
      public static void separator(){
        System.out.println("路径分隔符" + File.pathSeparator);
        System.out.println("名称分隔符" + File.separator);
      }
      // 2、文件操作
      public static void fileOpe() throws Exception{
        // 1. 创建文件
        if(!file.exists()){ // 是否存在
            File file = new File("路径");
            boolean b = file.creatNewFile();
            System.out.println("创建结果:" + b);
        }
        
        // 2. 删除文件
        // 2.1 直接删除
        file.delete(); // 成功 true
        // 2.2 使用 jvm 退出时删除
        file.deleteOnExit();
        
        // 3. 获取文件信息
        System.out.println("获取绝对路径" + file.getAbsolutePaht());
        System.out.println("获取路径" + file.getPath());
        System.out.println("获取文件名称" + file.getName());
        System.out.println("获取父目录" + file.getParent());
        System.out.println("获取文件长度" + file.length());
        System.out.println("文件创建时间" + new Date(file.lashModified()).toLocalString());
        
        // 4. 判断
        System.out.println("是否可写:" + file.canWrite());
        System.out.println("是否是文件:" + file.isFile());
        System.out.println("是否隐藏:" + file.isHidden());
      }
     
      // 3、文件夹操作
      public static void directoryOpe() throws Exception{
        // 1. 创建文件夹
        File dir = new File("路径");
        System.out.println(dir.toString());
        if(!dir.exists()){
          //dir.mkdir(); // 只能创建单级目录
          dir.mkdirs(); // 创建多级目录
        }
        
        // 2. 删除文件夹
        // 2.1 直接删除
        dir.delete(); // 只能删除最底层空目录
        // 2.2 使用 jvm 删除
        dir.deleteOnExit();
        
        // 3. 获取文件夹信息
        System.out.println("获取绝对路径" + dir.getAbsolutePaht());
        System.out.println("获取路径" + dir.getPath());
        System.out.println("获取文件名称" + dir.getName());
        System.out.println("获取夫目录" + dir.getParent());
        System.out.println("获取文件长度" + dir.length());
        System.out.println("文件夹创建时间" + new Date(dir.lashModified()).toLocalString());
        
        // 4. 判断
        System.out.println("是否是文件夹" + dir.isFile());
        System.out.println("是否隐藏" + dir.isHidden());
        
        // 5. 遍历文件夹
        File dir2 = new File("路径");
        String[] files = dir2.list();
        for(String string : files){
          System.out.println(string);
        }
        
        // FileFilter 接口的使用    
        File[] files2 = dir2.listFiles(new FileFilter(){      
          @Override
          public boolean accept(File pathname){
            if(pathname.getName().endsWith(".jpg")){
              return true;
            }
            return false;
          }
        });
        for(File file : files2){
          System.out.println(file.getName());
        }    
      }
    }
    

    FileFilter 接口:文件过滤器

    • 用来过滤文件(File对象);
    • public interface FileFilter
      • boolean accept(File pathname)
    • 当调用 File 类中的 listFiles() 方法时,支持传入 FileFilter 接口实现类,对获取文件进行过滤,只有满足条件的文件才可以出现在 listFiles() 的返回值中。
    File[] files2 = dir2.listFiles(new FileFilter(){      
          @Override
          public boolean accept(File pathname){
            if(pathname.getName().endsWith(".jpg")){
              return true;
            }
            return false;
          }
        });
    

    递归遍历文件夹

    public static void main(String[] args){
      listDir(new File("d:\\myfiles"));
    }
    public static void listDir(File dir){
      File[] files = dir.listFiles();
      // 打印文件夹下文件
      System.out.println(dir.getAbsolutePath());
      // 判断文件夹是否为空
      if(files != null && files.length > 0){
        for(File file : files){
          // 判断是否是文件夹
          if(file.isDirectory()){
            // 如果是文件夹,递归调用listDir,遍历文件
            listDir(file); // 递归
          }else {
            // 打印子文件夹内文件
            System.out.println(file.getAbsolutePath());
          }
        }
      }
    }
    

    递归删除文件夹

    public static void deleteDir(File dir){
      File[] files = dir.listFiles();
      // 判断是否为空
      if(files != null && files.length > 0){
        for(File file : files){
          // 判断是否是文件夹
          if(file.idDirectory()){
            deleteDir(file); // 递归
          }else{
            // 删除子文件夹文件
            System.out.println(file.getAbsolutePath() + " 删除:" + file.delete());
          }
        }
      }
      // 删除文件
      System.out.println(dir.getAbsolutePath() + " 删除:" + dir.delete());
    }
    

    补充:Properties

    • Properties:属性集合
    • 特点:
      1. 存储属性名和属性值
      2. 属性名和属性值都是字符串类型
      3. 没有泛型
      4. 和流有关
    package com.base.demo08;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.PrintWriter;
    import java.util.Properties;
    import java.util.Set;
    
    /*
     * Properties 集合的使用
     * */
    public class Demo03 {
        public static void main(String[] args) throws Exception {
            // 1.创建集合
            Properties properties = new Properties();
            // 2.添加数据
            properties.setProperty("username", "Liu");
            properties.setProperty("age", "20");
            System.out.println(properties.toString());
    
            // 3.遍历
            // 3.1--------------keySet---------------
            // 3.2--------------entrySet---------------
            // 3.3--------------stringPropertyNames()---------------
            Set<String> pronames = properties.stringPropertyNames();
            for (String pro : pronames) {
                // 打印键、值
                System.out.println(pro + "=========" + properties.getProperty(pro));
            }
    
            // 4.和流有关的方法
            // ---------1.list方法----------
            // 创建打印流
            PrintWriter pw = new PrintWriter("d:\\print.txt");
            properties.list(pw);
            pw.close();
    
            // ---------2.store方法(保存)----------
            // 创建流
            FileOutputStream fos = new FileOutputStream("d:\\store.properties");
            properties.store(fos, "注释");
            fos.close();
    
            // ---------3.load方法(加载)----------
            // 创建对象
            Properties properties2 = new Properties();
            // 创建流
            FileInputStream fis = new FileInputStream("d:\\store.properties");
            properties2.load(fis);
            fis.close();
            System.out.println(properties2.toString());
        }
    }
    

    相关文章

      网友评论

        本文标题:Java 基础 07. Java I/O 流

        本文链接:https://www.haomeiwen.com/subject/gxqofrtx.html