• 文件和IO流


    一、File类

    在认识io流之前需要先认识FIle类,因为file类用来表示文件或文件夹的。

    通过File类能对文件或文件夹进行新建、删除、重命名操作

    1.1)File类的常用构造器

    public File(String pathname):
    以pathname为路径创建File对象,可以是绝对路径或者相对路径

    public File(String parent,String child)
    以parent为父路径,child为子路径创建File对象。

    public File(File parent,String child)
    根据一个父File对象和子文件路径创建File对象

    1.2) File类的创建功能

    public boolean createNewFile()
    创建文件。若文件存在,则不创建,返回false

    public boolean mkdir() :
    创建文件目录。如果此文件目录存在,就不创建了。
    如果此文件目录的上层目录不存在,也不创建。

    public boolean mkdirs() :
    创建文件目录。如果上层文件目录不存在,一并创建

    而IO流则是对文件或文件夹进行读写操作的。

    1.3)File类的删除功能

    public boolean delete():
    删除文件或者文件夹

    1.4)File类的获取功能

     public String getAbsolutePath():获取绝对路径
     public String getPath() :获取路径
     public String getName() :获取名称
     public String getParent():获取上层文件目录路径。若无,返回null
     public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
     public long lastModified() :获取最后一次的修改时间,毫秒值
     public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
     public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组

    1.5)File类的判断功能

     public boolean isDirectory():判断是否是文件目录
     public boolean isFile() :判断是否是文件
     public boolean exists() :判断是否存在
     public boolean canRead() :判断是否可读
     public boolean canWrite() :判断是否可写
     public boolean isHidden() :判断是否隐藏

    二、IO流

    2.1)流的分类

    根据流向分:
    输入流和输出流
    在这里插入图片描述

    根据数据单位分:
    字节流和字符流

    一个字符等于两个字节

    根据角色分:
    节点流和处理流

    如果操作的对象是文件,则该流是节点流;
    如果操作的对象是流,则该流是处理流

    2.2)流的体系结构

    抽象基类

    InputStream
    OutputStream
    Reader
    Writer

    节点流:

    FileInputStream
    FileOuptStream
    FileReader
    FileWriter

    缓存流:

    BufferedInputStream
    BufferedOutputStream
    BufferedReader
    BufferedWriter

    2.3)字符流

    FileReader

    字符输入流

    从文件中的数据写入到
    可以通过以下两种方式读取,两种方式都是读取到最后一个字符为-1时,则到达文件末尾

    每次读取一个字符

     while ((read=fileReader.read()) != -1) {
       System.out.print((char) read);
     }
    
    • 1
    • 2
    • 3
    @Test
    public void test1() {
         File file = new File("src/file/hello.txt");
         FileReader fileReader = null;
         try {
             fileReader = new FileReader(file);
             System.out.println(file.getAbsolutePath());
             int read;
             while ((read=fileReader.read()) != -1) {
                 System.out.print((char) read);
             }
         } catch (IOException e) {
             e.printStackTrace();
         } finally {
             try {
                 fileReader.close();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    每次读取一个数组

     char[] chars=new char[5];
     int len;
     while ((len=fileReader.read(chars))!=-1){
         for (int i=0;i<len;i++){
             System.out.print(chars[i]);
         }
         System.out.println();
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    @Test
    public void test2(){
        File File2=new File("src/file/hello.txt");
        FileReader fileReader = null;
        try {
            fileReader=new FileReader(File2);
            char[] chars=new char[5];
            int len;
            while ((len=fileReader.read(chars))!=-1){
                for (int i=0;i<len;i++){
                    System.out.print(chars[i]);
                }
                System.out.println();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (fileReader!=null){
                    fileReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    FileWriter

    字符输出流
    将字符从内存中写到文件(硬盘)

    1、如果文件不存在,则进行创建
    2、如果文件存在:

    使用FIleWriter(file,true),则将字符追加到文件中
    使用FileWriter(file,false)或FileWriter(file),则写入的内容覆盖原有的内容

     fileWriter=new FileWriter(file2,true);
     char[] chars=new char[10];
     int len;
     while ((len=fileReader.read(chars))!=-1){
        fileWriter.write(chars);
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.4) 字节流

    FileInputStream

    字节输入流,可以将字节数据读取到内存中

    使用该流可以读取图片,视频,音频等

    File file1=new File("E:\\temp\\aof1.png");
    fileInputStream=new FileInputStream(file1);
     byte[] bytes=new byte[10];
     int len;
     while ((len=fileInputStream.read(bytes))!=-1){
         System.out.println(new String(bytes,0,len));
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    int read()
    从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因
    为已经到达流末尾而没有可用的字节,则返回值 -1。

    int read(byte[] b)
    从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。如果因为已
    经到达流末尾而没有可用的字节,则返回值 -1。否则以整数形式返回实际读取
    的字节数。

    int read(byte[] b, int off,int len)
    将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取
    的字节也可能小于该值。以整数形式返回实际读取的字节数。如果因为流位于
    文件末尾而没有可用的字节,则返回值 -1。

    FileOutputStream

    File write=new File("src/file/hello.gif");
    FileOutputStream fileOutputStream=new FileOutputStream(write,true);
    byte[] bytes=new byte[10];
    int len;
     while ((len=fileInputStream.read(bytes))!=-1){
         //System.out.println(new String(bytes,0,len));
         fileOutputStream.write(bytes);
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    public void flush()throws IOException:

    刷新此输出流并强制写出所有缓冲的输出字节,调用此方法指示应将这些字节立
    即写入它们预期的目标。

    void write(int b)
    将指定的字节写入此输出流。write 的常规协定是:向输出流写入一个字节。要写
    入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。 即写入0~255范围的。

    void write(byte[] b)
    将 b.length 个字节从指定的 byte 数组写入此输出流。write(b) 的常规协定是:应该
    与调用 write(b, 0, b.length) 的效果完全相同。

    void write(byte[] b,int off,int len)
    将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流

    2.5)缓冲流

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

    BufferedInputStream 和 BufferedOutputStream
    BufferedReader 和 BufferedWriter

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

    读文件

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

    写文件

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

    关闭流

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

    举个例子:

    FileReader fileReader = null;
    FileWriter fileWriter = null;
    
    BufferedReader bufferedReader = null;
    BufferedWriter bufferedWriter = null;
    
    fileReader = new FileReader(source);
    fileWriter = new FileWriter(target);
    bufferedReader = new BufferedReader(fileReader);
    bufferedWriter = new BufferedWriter(fileWriter);
    
    String s = null;
    while ((s = bufferedReader.readLine()) != null) {
        bufferedWriter.write(s);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.6)转换流(属于字符流)

    转换流提供了在字节流和字符流之间的转换

    Java API提供了两个转换流:

    InputStreamReader:将InputStream转换为Reader
    OutputStreamWriter:将Writer转换为OutputStream

    在这里插入图片描述

    InputStreamReader

    将字节输入流转换为字符输入流

    OutputStreamWriter

    将字节输出流转为字符输出流

    编码:将字符转为字节(看得懂的转成看不懂的)
    解码:将字节转为字符(看不懂的转成看得懂的)

    转换流复制文件

    @Test
    public void test1() {
       File read = null;
       File write = null;
       FileInputStream fileInputStream = null;
       FileOutputStream fileOutputStream = null;
       OutputStreamWriter outputStreamWriter=null;
       InputStreamReader inputStreamReader=null;
       try {
           read = new File("hell01.txt");
           write = new File("temp.txt");
           fileInputStream = new FileInputStream(read);
           fileOutputStream = new FileOutputStream(write);
           inputStreamReader=new InputStreamReader(fileInputStream,"utf-8");
           outputStreamWriter=new OutputStreamWriter(fileOutputStream,"utf-8");
           char[] chars=new char[10];
           int len = 0;
           while ((len = inputStreamReader.read(chars)) != -1) {
               System.out.println();
               outputStreamWriter.write(String.valueOf(chars));
           }
       } catch (IOException e) {
           e.printStackTrace();
       } finally {
           if (inputStreamReader != null) {
               try {
                   inputStreamReader.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
           if (outputStreamWriter != null) {
               try {
                   outputStreamWriter.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
       }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    2.7)对象流

    ObjectInputStream和OjbectOutputSteam

    用于存储和读取基本数据类型数据或对象的处理流。

    序列化:ObjectOutputStrem保存基本数据类型或对象
    反序列化:ObjectInputStream读取基本数据类型或对象

    注意
    ObjectOutputStream和ObjectInputStream不能序列化 static和transient修
    饰的成员变量

    对象的序列化

    特点:

    1、可以将基本数据类型或java对象转换成二进制流;
    2、任何实现serializeable接口的对象转换成的字节数据都可以在保存和传输时被还原
    3、如果要进行网络传输,就必须进行序列化
    4、如果要让对象支持序列化就必须实现Serializable或Externalizable接口
    5、凡是实现Serializable接口的类 必须 有一个表示序列化标识符的静态变量
    private static final long serialVersionUID
    6、除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)

    为什么凡是实现Serializable接口的类 必须 有一个表示序列化标识符的静态变量?

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

    举个例子:(为了让代码看起来少一点,这里没有在finally中关闭资源)

    演示不加入serialVersionUID

    public class Person implements Serializable {
       // public static final long serialVersionUID=1L;
    
        private String name;
        private String sex;
    
        public Person(String name, String sex) {
            this.name = name;
            this.sex = sex;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", sex='" + sex + '\'' +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    @Test
    public void test1(){
        serializableString(); // 序列化
        unSerializableString(); // 反序列化
    }
    
    private void serializableString() {
        try {
            ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream("data.txt"));
            Person person=new Person("张三","男");
            objectOutputStream.writeObject(person);
            objectOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private void unSerializableString() {
        try {
            ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream("data.txt"));
            Person person= (Person) objectInputStream.readObject();
            System.out.println(person.toString());
            objectInputStream.close();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在序列化之后没有对类进行更改,发现反序列化之后可以恢复
    在这里插入图片描述
    如果在·序列化之后,修改了类

    public class Person implements Serializable {
       // public static final long serialVersionUID=1L;
    
        private String name;
        private String sex;
        pricate int age;
    
        public Person(String name, String sex) {
            this.name = name;
            this.sex = sex;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", sex='" + sex + '\'' +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    执行反序列化操作

     @Test
     public void test1(){
          unSerializableString(); // 反序列化
      }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    这是因为通过serialVersionUID可以识别出是哪一个类,即使改变了也可以反序列化处理,但是 如果没有serialVersionUID,就不知道是哪个类,所有就无法反序列化。

  • 相关阅读:
    【css】svg动画动态骷髅旋转html
    传统制造企业进行数字化转型,是翻身还是翻船?
    前端老赵一次给你讲透“微前端”架构
    elementui 弹窗展示自动校验表单项bug
    SpringBoot——yml配置文件的书写和读取
    python+django+nodejs+vue的影视信息网站
    圆心科技,很焦虑?
    【云原生生态圈】:服务快速上云--Docker部署SpringBoot案例详解
    Kruise Rollout:基于 Lua 脚本的可扩展流量调度方案
    想要软件测试效果好,搭建好测试环境是前提
  • 原文地址:https://blog.csdn.net/weixin_42371679/article/details/125381573