JavaEE 初阶第十六期:文件 IO 的 “管道艺术”(中)

发布于:2025-08-16 ⋅ 阅读:(12) ⋅ 点赞:(0)

专栏:JavaEE初阶起飞计划

个人主页:手握风云

目录

一、Java文件操作

1.1. 方法

二、Java文件内容读取

2.1. 数据流

2.2. InputStream

2.3. 文件泄露


一、Java文件操作

1.1. 方法

  • 打印路径下的文件
import java.io.File;
import java.util.Arrays;

public class Demo1 {
    public static void main(String[] args) {
        File file = new File("D:\\java-ee-beginner\\Test8.8.1");

        System.out.println(Arrays.toString(file.list())); // 返回当前目录下的文件名
        System.out.println(Arrays.toString(file.listFiles())); // 返回当前目录下的文件对象
    }
}

  • 创建目录
package myFile;

import java.io.File;

public class Demo2 {
    public static void main(String[] args) {
        File file = new File("./test1/aaa/bbb");
        file.mkdir(); //创建File对象的单层目录
        file.mkdirs(); // 创建File对象的多层目录
    }
}

  • 重命名
package myFile;

import java.io.File;
import java.io.IOException;
import java.util.Scanner;

public class Demo3 {
    public static void main(String[] args) throws IOException {
        File file1 = new File("./test.txt");
        if (!file1.exists()) {
            file1.createNewFile();
        }
        Scanner in = new Scanner(System.in);
        System.out.println("请输入任意内容:");
        in.next();
        File file2 = new File("./test2.txt");
        file1.renameTo(file2);// 重命名文件名称
    }
}

            该方法不光可以修改文件名称,还可以修路径。

    • 用户权限
    package myFile;
    
    import java.io.File;
    
    public class Demo4 {
        public static void main(String[] args) {
            File file = new File("./test");
            file.canRead();//判断文件是否可读
            file.canWrite();//判断文件是否可写
        }
    }

            上述两个方法在Windows上面运行结果不太明显,在Linux上运行才明显。

    二、Java文件内容读取

    2.1. 数据流

            文件内容操作大致分为读文件(硬盘的数据读到内存)和写文件(把内存的数据写到内存)。这时我们就需要借助流对象进行文件内容操作。

            流对象,我们类比为水流。比如我们要接100ml水,分1次接100ml,或者分2次接50ml。同样对于100byte的数据,分1次读取100byte,或者分2次读取50byte。各种编程语言,围绕文件的操作都统称为“流”。

            Java中通过一系列大类表示“流对象”,但总体上可以分为两类:字节流和字符流。字节流(InputStream、OutputStream)以字节为单位,一次最少读一个字节;字符流(Reader、Writer)以字符为单位,一次最少读写一个字符。

    2.2. InputStream

    public abstract class InputStream implements Closeable

            InputStream只是⼀个抽象类,要使用还需要具体的实现类。我们现在只关心从⽂件中读取,所以使用FileInputStream。

    InputStream inputStream = new FileInputStream("./test.txt"); //创建一个文件输入流对象

            要想实现文件读取的操作,要使用read方法。无参数版本一次读取⼀个字节的数据,返回-1代表已经完全读完了。1个参数版本最多读取b.length字节的数据到b中,返回实际读到的量,-1代表以及读完了。3个参数版本最多读取len-off字节的数据到b中,放在从off开始,返回实际读到的数量,-1代表以及读完了。

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class Demo5 {
        public static void main(String[] args) throws IOException {
            //创建一个文件输入流对象,”打开文件“的过程
            InputStream inputStream = new FileInputStream("./test.txt");
            while (true) {
                int c = inputStream.read();
                if (c == -1) {
                    // 读取完毕
                    break;
                }
                System.out.printf("0x%x\n", c);
            }
        }
    }

            我们在项目路径下新建记事本,然后内容保存为"Hello world!",运行就会出现如下效果,各个字符对应的ASCII码值。

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class Demo6 {
        public static void main(String[] args) throws IOException {
            InputStream inputStream = new FileInputStream("./test.txt");
            while (true) {
                byte[] bytes = new byte[1024];
                int n = inputStream.read(bytes);
                if (n == -1) {
                    break;
                }
                for (int i = 0; i < n; i++) {
                    System.out.printf("0x%x\n", bytes[i]);
                }
            }
        }
    }

            此处的字节数组是一个输出型参数,我们实现构造好数组元素全为0的数组,然后填充在read方法内部。这种方式适用于需要返回多个结果或批量数据的场景,避免了方法只能有一个返回值的限制。我们可以想象在食堂打饭时,需要拿着餐盘递给阿姨,装完饭后,阿姨把成盛满饭的餐盘端给我们。

            第三个方法与第二个方法逻辑一致,只不过打印顺序是从off下标开始。

    2.3. 文件泄露

            我们在上面的打开文件和读取文件之后,还有一个重要的操作,就是关闭文件。inputSream.close();进程PCB中有一个属性,文件描述符表(通过顺序表实现),每次打开一个文件,都会在这个表里面插入一个元素。但是文件描述符表是不能扩容的,如果光打开文件不关闭,就会把表里的内容消耗殆尽,再想打开其他文件就会失败。

            我们看下面一段代码:下面的代码存在一些问题,当read方法出现了异常,会直接跳过close()方法

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class Demo7 {
        private static void readFile() {
            try {
                InputStream inputStream = new FileInputStream("./test.txt");
                while (true) {
                    byte[] bytes = new byte[1024];
                    int n = inputStream.read(bytes);
                    if (n == -1) {
                        break;
                    }
                    for (int i = 0; i < n; i++) {
                        System.out.printf("%x", bytes[i]);
                    }
                    System.out.println();
                }
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public static void main(String[] args) {
            readFile();
        }
    }

            为了解决上面的问题,我们可以把close方法放进finally代码块里面。

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class Demo7 {
        private static void readFile() {
            InputStream inputStream = null;
            try {
                inputStream = new FileInputStream("./test.txt");
                while (true) {
                    byte[] bytes = new byte[1024];
                    int n = inputStream.read(bytes);
                    if (n == -1) {
                        break;
                    }
                    for (int i = 0; i < n; i++) {
                        System.out.printf("%x", bytes[i]);
                    }
                    System.out.println();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (inputStream == null) {
                        inputStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            readFile();
        }
    }

            虽然可以解决上面的问题,但又引入了新的问题,就是代码的美观。

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class Demo7 {
        private static void readFile1() {
            InputStream inputStream = null;
            try {
                inputStream = new FileInputStream("./test.txt");
                while (true) {
                    byte[] bytes = new byte[1024];
                    int n = inputStream.read(bytes);
                    if (n == -1) {
                        break;
                    }
                    for (int i = 0; i < n; i++) {
                        System.out.printf("%x", bytes[i]);
                    }
                    System.out.println();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (inputStream == null) {
                        inputStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        private static void readFile2() {
            // try with resource 简化语法
            // try语句执行结束之后,会自动调用close方法
            try (InputStream inputStream = new FileInputStream("./test.txt")) {
                while (true) {
                    byte[] bytes = new byte[1024];
                    int n = inputStream.read(bytes);
                    if (n == -1) {
                        break;
                    }
                    for (int i = 0; i < n; i++)
                        System.out.printf("%x", bytes[i]);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            readFile2();
        }
    }

    网站公告

    今日签到

    点亮在社区的每一天
    去签到