• 【JavaEE】文件操作和IO


    1 什么是文件?

    针对硬盘这种持久化存储的I/O设备,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念

    2 文件路径

    文件路径就是指咱们文件系统中一个文件/目录(文件夹)的具体位置

    由于文件系统是以树形结构来组织文件和目录,所以文件路径就是从树根节点出发,沿着树杈往下走,直到到达目标文件,这中间所经过的内容

    2.1 绝对路径

    Windows是从“此电脑”开始的,表示路径的时候可以忽略“此电脑”,直接从盘符开始

    例如:F:\人工智能程序设计\我的python案例\Test1.py

    实际表示路径是通过字符串来表示,每个目录之间使用‘/’(斜杠)来分割.(只有Windows采用‘\’(反斜杠)来分割)

    从盘符开始一层层往下找,这个过程,得到的路径就叫绝对路径

    2.2 相对路径

    从给定的目标开始,一层一层往下找,这个过程得到的路径就是相对路径

    eg:
    在这里插入图片描述

    其中:
    ‘.’是一个特殊符号,在相对路径中代表当前目录
    ‘. .’表示当前目录的上级目录

    3 文本文件和二进制文件

    文本文件存储的是被字符集编码的文本
    二进制文件存储的是二进制文件,不被字符集限制

    4 文件系统操作

    java标准库给我们提供了File类,File对象是对硬盘上一个文件的抽象
    (文件是储存在硬盘上的,直接用代码操作硬盘不方便,就在内存中创建一个对应的对象,操作这个内存中的对象就可以间接的影响到硬盘中的文件的情况了~~遥控器)

    4.1 构造File对象

    构造的过程可以使用相对路径/绝对路径来进行初始化,这个路径指向的文件可以是真实存在的也可以是不存在的
    在这里插入图片描述

    4.2 File提供的方法

    在这里插入图片描述

    get方法代码演示:

    import java.io.File;
    import java.io.IOException;
    
    public class IO_Test1 {
        public static void main(String[] args) throws IOException {
            File file = new File("./cat.jpg");
            System.out.println(file.getParent());   //返回 File 对象的父目录文件路径
            System.out.println(file.getName());     //返回 FIle 对象的纯文件名称
            System.out.println(file.getPath());       //返回 File 对象的文件路径
            System.out.println(file.getAbsolutePath());       //返回 File 对象的绝对路径
            System.out.println(file.getCanonicalPath());        //返回 File 对象的修饰过的绝对路径
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述
    普通文件的创建和删除:

    import java.io.File;
    import java.io.IOException;
    
    public class IO_Test2 {
        public static void main(String[] args) throws IOException {
            // 在相对路径中, ./ 通常可以省略
            File file = new File("hello_IO.txt");       // 该文件不存在
    
            System.out.println(file.exists());      //判断 File 对象描述的文件是否真实存在
            System.out.println(file.isDirectory());     //判断 File 对象代表的文件是否是一个目录
            System.out.println(file.isFile());      //判断 File 对象代表的文件是否是一个普通文件
    
            //创建文件
            file.createNewFile(); //根据 File 对象,自动创建一个空文件。成功创建后返回 true
            //创建后该文件存在
            System.out.println(file.exists());      //判断 File 对象描述的文件是否真实存在
            System.out.println(file.isDirectory());     //判断 File 对象代表的文件是否是一个目录
            System.out.println(file.isFile());      //判断 File 对象代表的文件是否是一个普通文件
            
            //删除文件
            file.delete();
            System.out.println("删除文件之后");
            System.out.println(file.exists());
        }
    }
    
    • 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

    在这里插入图片描述

    5 文件内容操作

    5.1 字符流

    什么是字符流?

    针对文本文件,提供了一组类,统称为“字符流”

    典型代表:Reader , Writer。 读写的基本单位是字符

    在这里插入图片描述

    在这里插入图片描述

    InputStream使用方法

    🚀打开文件和关闭文件

    InputStream是抽象类:
    在这里插入图片描述
    关于 InputStream 的实现类有很多,我们现在只关心从文件中读取,所以使用 FileInputStream类

    InputStream inputStream = new FileInputStream("f:/test.txt");
    
    • 1

    ![在这里插入图片描述](https://img-blog.csdnimg.cn/81be2241a32d4f1795ff001901560a4e.png
    注意!!!:这里有了打开文件的操作,后面需要手动释放资源(文件描述符)!!!! inputStream.close();
    进程的PCB结构中又“文件描述符表”,其记录了当前进程都打开了哪些文件,每次打开文件,就会在表中申请到一个位置~这个表可以视为一个数组,数组的下标就是文件描述符,数组元素就是这个文件在内核中的结构体的表示。
    由于这个表长度是有限的不能无休止的打开又不释放,一旦满了再尝试打开就会打开失败,造成文件资源泄露!!!

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class IO_Test3 {
        public static void main(String[] args) throws IOException {
            // 这个过程, 相当于 C 中的 fopen , 文件的打开操作
            InputStream inputStream = new FileInputStream("f:/test.txt");
            inputStream.close();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    执行中间,可能会出一些问题,比如return或者抛异常,就会导致close执行不到!
    所以我们使用try...finally

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class IO_Test3 {
        public static void main(String[] args) throws IOException {
            // 这个过程, 相当于 C 中的 fopen , 文件的打开操作
            InputStream inputStream = null;
            try {
                inputStream = new FileInputStream("f:/test.txt");
            }
            finally {
                inputStream.close();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    但是上面这个代码太麻烦了(丑)
    我们使用try with resources (带有资源的try操作,会在try结束自动执行close关闭操作)

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class IO_Test3 {
        public static void main(String[] args) throws IOException {
    
            try(InputStream inputStream = new FileInputStream("f:/test.txt")) {
                //打开文件和关闭文件
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    🚀读文件:

    InputStream提供的read方法有三个版本:
    在这里插入图片描述

    在这里插入图片描述
    其中read的无参数版本是一次读一个字节(一次返回一个字节)
    但是我们需要用int来接受read的返回值====>

    int b = inputStream.read();
    
    • 1

    在这里插入图片描述
    完整代码:

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class IO_Test3 {
        public static void main(String[] args) throws IOException {
    
            try(InputStream inputStream = new FileInputStream("f:/test.txt")) {
                //读文件
                // read 一次返回的是一个字节. 但是此处的返回值类型是 int !!!
                while (true) {
                    int b = inputStream.read();
                    if (b == -1) {
                        // 读到末尾了, 结束循环即可
                        break;
                    }
                    System.out.printf("%x\n", b);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    🚀 写文件
    package io;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    
    public class IODemo7 {
        public static void main(String[] args) {
            try (OutputStream outputStream = new FileOutputStream("d:/test.txt")) {
                outputStream.write(97);
                outputStream.write(98);
                outputStream.write(99);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    6 文件操作案例

    扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)
    解:
    在这里插入图片描述

    import java.io.*;
    import java.util.Scanner;
    
    public class IO_Test4 {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            // 1. 先让用户指定一个要搜索的根目录
            System.out.println("请输入要扫描的根目录: ");
            File rootDir = new File(scanner.next());
            if (!rootDir.isDirectory()) {
                System.out.println("输入有误, 您输入的目录不存在!");
                return;
            }
            // 2. 让用户输入一个要查询的词.
            System.out.println("请输入要查询的词: ");
            String word = scanner.next();
    
            // 3. 递归的进行目录/文件的遍历了
            scanDir(rootDir, word);
        }
    
        private static void scanDir(File rootDir, String word) {
            // 列出当前的 rootDir 中的内容. 没有内容, 直接递归结束
            File[] files = rootDir.listFiles();
            if (files == null) {
                // 当前 rootDir 是一个空的目录, 这里啥都没有.
                // 没必要往里递归了
                return;
            }
            // 目录里有内容, 就遍历目录中的每个元素
            for (File f : files) {
                System.out.println("当前搜索到: " + f.getAbsolutePath());
                if (f.isFile()) {
                    // 是普通文件
                    // 打开文件, 读取内容, 比较看是否包含上述关键词
                    String content = readFile(f);
                    if (content.contains(word)) {
                        System.out.println(f.getAbsolutePath() + " 包含要查找的关键字!");
                    }
                } else if (f.isDirectory()) {
                    // 是目录
                    // 进行递归操作
                    scanDir(f, word);
                } else {
                    // 不是普通文件, 也不是目录文件, 直接跳过
                    continue;
                }
            }
        }
    
        private static String readFile(File f) {
            // 读取文件的整个内容, 返回出来.
            // 使用字符流来读取. 由于咱们匹配的是字符串, 此处只能按照字符流处理, 才是有意义的.
            StringBuilder stringBuilder = new StringBuilder();
            try (Reader reader = new FileReader(f)) {
                // 一次读一个字符, 把读到的结果给拼装到 StringBuilder 中. 统一转成 String
                while (true) {
                    int c = reader.read();
                    if (c == -1) {
                        break;
                    }
                    stringBuilder.append((char)c);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return stringBuilder.toString();
        }
    }
    
    • 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
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
  • 相关阅读:
    广州地铁14号线新市墟站开建,白云区居民即将开启双线换乘模式!
    Windows性能监控工具ypeperf
    带有 Vagrant 和 Virtualbox 的 Elasticsearch 集群
    马斯克 0 元垫底、年薪近 1 亿美元的库克仅排第四?“魔幻”的 CEO 薪酬排名曝光
    LeetCode 63. 不同路径 II
    从哪些方面分析Linux内核源码
    postman拦截浏览器请求
    FPGA面试笔试一些基础概念题目
    前端面经 在地址栏输入URL,到页面呈现,中间会发生
    gRPC 自定义负载均衡算法
  • 原文地址:https://blog.csdn.net/m0_68101404/article/details/133908911