• 【Java 基础语法】Java 的文件操作



    Java 操作文件包括了两个层面:

    • 在文件系统的层面上来操作文件,包括创建文件、删除文件、创建目录、拷贝文件等等。
    • 操作文件里保存的数据,包括读文件、写文件。

    1. 在文件系统层面操作文件

    1.1 File 类介绍

    Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。不过有 File 对象,并不代表对应的文件真实存在。

    1.2 File 常见属性

    属性修饰符及类型说明
    pathSeparatorstatic String依赖于系统的路径分隔符,String 类型的表示
    pathSeparatorstatic char依赖于系统的路径分隔符,char 类型的表示

    1.3 File 构造方法

    构造方法说明
    File(File parent, String child)根据父目录+孩子文件路径,创建一个新的 File 实例
    File(String pathname)根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径
    File(String parent, String child)根据父目录路径+孩子文件路径,创建一个新的 File 实例

    1.4 File 常用方法

    方法返回值类型说明注意
    getParent()String返回 File 对象的父目录文件路径
    getName()String返回 File 对象的纯文件名称
    getPath()String返回 File 对象的文件路径
    getAbsolutePath()String返回 File 对象的绝对路径
    getCanonicalPath()String返回 File 对象的修饰过的绝对路径如果绝对路径的值为:d:/././test.txt,那么修饰过的绝对路径就为:d:/test.txt。
    exists()boolean判断 File 对象描述的文件是否真实存在
    isDirectory()boolean判断 File 对象代表的文件是否是一个目录
    isFile()boolean判断 File 对象代表的文件是否是一个普通文件
    createNewFile()boolean根据 File 对象,自动创建一个空文件。成功创建后返回 true如果文件路径不正确或者没有权限,则可能创建失败。
    delete()boolean根据 File 对象,删除该文件。成功删除后返回 true如果文件路径不正确或者没有权限,则可能删除失败。
    deleteOnExit()void根据 File 对象,标注文件将被删除,删除动作会到 JVM 运行结束时才会进行
    list()String[]返回 File 对象代表的目录下的所有文件名
    listFiles()File[]返回 File 对象代表的目录下的所有文件,以 File 对象表示
    mkdir()boolean创建 File 对象代表的目录
    mkdirs()boolean创建 File 对象代表的目录,如果必要,会创建中间目录
    renameTo(File dext)boolean重命名文件或移动文件,当目录为空时也可以重命名目录
    canRead()boolean判断用户是否对文件有可读权限
    canWrite()boolean判断用户是否对文件有可写权限

    2. 操作文件里的数据

    文件内容的操作包括读文件和写文件,而对于这两种操作 Java 又提供了两种不同的类:

    读类写类说明
    InputStreamOutputStream字节流,针对二进制文件进行读写,操作基本单位是字节
    ReaderWriter字符流,针对文本文件进行读写,操作基本单位是字符
    • 字节流: 它处理单元为1个字节,操作字节和字节数组,存储的是二进制文件,如果是音频文件、图片、歌曲,就用字节流。
    • 字符流: 它处理的单元为2个字节的 Unicode 字符,分别操作字符、字符数组或字符串,字符流是由 Java 虚拟机将字节转化为2个字节的 Unicode 字符为单位的字符而成的,如果是关系到中文(文本)的,用字符流更好。
    • 所有文件都是以字节的形式储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列。
    • 字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串。
    • 字节流提供了处理任何类型的 IO 操作的功能,但它不能直接处理 Unicode 字符,而字符流就可以。
    • 字节流在操作的时候本身不会用到缓冲区的,是与文件本身直接操作的;而字符流在操作的时候会使用到缓冲区的。
    • 其中 InputStream/OutputStream 和 Reader/Writer 都实现了 Closeable 接口,所以可以不主动通过 close 方法去关闭该资源,而是通过代码可读性更高的 try-with-resource 操作在 try 中的内容结束后,无论是否有异常都关闭该资源。
    • 使用 OutputStream 或 writer 打开文件默认会清空之前的文件内容

    2.1 操作字节流数据

    2.1.1 InputStream

    InputStream 是一个抽象类,使用时需要使用具体的实现类。InputStream 的实现类很多,针对不同的输入设备都可以对应一个实现类,其中针对文件读取的实现类是 FileInputStream。

    FileInputStream 构造方法:

    构造方法说明
    FileInputStream(File file)利用 File 构造对应文件输入流
    FileInputStream(String name)利用文件路径构造对应文件输入流

    InputStream 核心方法:

    方法返回值类型说明
    read()int一次读取一个字节的数据,如果返回 -1 表示文件读完了
    read(byte[] b)int一次最多读取 b.length 字节的数据到 b 中,返回值为实际读到的字节数量,如果返回 -1 表示文件读完了
    read(byte[] b, int off, int len)int一次最多读取 len 个字节到 b 中,并从 off 的位置开始存放,返回值为实际读到的字节数量,如果返回 -1 表示文件读完了
    close()void关闭字节流

    为什么 read 方法的返回值是 Int 类型?

    对于 read 方法的返回值,当读取的是数字和英文时,返回值是对应的 ascii 码;当读取的是汉字时,返回的是汉字的机内码,比如使用的是 GBK 编码方式,返回的就是 GBK 的内部编码。read 方法每次从 inputstream 中读取一个字节,而一个字节是8位,但当最高位是1的时候,二进制对应的 ascii 码值就是复数,而 ascii 是没有负数的,所以用 byte 类型表示不了。并且 11111111 对应的十进制值是 -1,而返回 -1 表示文件读取完毕了,则后面的数据就不会读了,因此 byte 类型不适合,int 类型则可以解决这个问题。

    示例代码: 使用 read() 方法读取文件内容

    public class Demo1 {
        public static void main(String[] args) throws IOException {
            File file = new File("./test.txt");
            StringBuilder sb = new StringBuilder();
            try (InputStream inputStream = new FileInputStream(file)){
                while(true) {
                    int b = inputStream.read();
                    if(b == -1){
                        break;
                    }
                    sb.append((char) b);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(sb.toString());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    示例代码: 使用 read(byte[] b) 方法读取文件内容

    public class Demo1 {
        public static void main(String[] args) throws IOException {
            File file = new File("./test.txt");
            byte[] buffer = new byte[1024];
            try (InputStream inputStream = new FileInputStream(file)){
                while(true) {
                    int len = inputStream.read(buffer);
                    if(len == -1){
                        break;
                    }
                    String s = new String(buffer, 0, len, "utf-8");
                    System.out.println(s);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.1.2 OutputStream

    OutputStream 是一个抽象类,使用时需要使用具体的实现类。OutputStream 的实现类很多,针对不同的输出设备都可以对应一个实现类,其中针对文件读取的实现类是 FileOutputStream。

    FileOutputStream 构造方法:

    构造方法说明
    FileOutputStream(File file)利用 File 构造对应文件输出流
    FileOutputStream(String name)利用文件路径构造对应文件输出流
    FileOutputStream(File file, boolean append)append 表示是否追加数据到文件的末尾,为 true 表示追加,为 false 表示情空之前的内容重新加入
    FileOutputStream(String name, boolean append)append 表示是否追加数据到文件的末尾,为 true 表示追加,为 false 表示情空之前的内容重新加入

    OutputStream 核心方法:

    方法返回值类型说明
    write()int一次写入一个字节的数据
    write(byte[] b)int一次最多写入 b.length 字节的数据到 b 中,返回值为实际写入的字节数量
    write(byte[] b, int off, int len)int一次最多写入 len 个字节到 b 中,并从 off 的位置开始存放,返回值为实际写入到的字节数量
    close()void关闭字节流

    示例代码:

    public class Demo1{    
    	public static void main(String[] args) throws IOException {
            File in = new File("./in.txt");
            File out = new File("./out.txt");
            byte[] buffer = new byte[1024];
            try (InputStream inputStream = new FileInputStream(in);
                 OutputStream outputStream = new FileOutputStream(out)) {
                while (true) {
                    int len = inputStream.read(buffer);
                    if (len == -1) {
                        break;
                    }
                    outputStream.write(buffer, 0, len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.1.3 BufferedInputStream

    BufferedInputStream 也是 InputStream 的具体实现类,相比于 FileInputStream 优化了系统调用,即通俗解释为:将数据保存了缓存区,但是减少磁盘 IO 并不是 BufferedInputStream 来做的,而是 OS 来做的。OS 根据局部性原理,会预读部分的数据到内存缓存区,这样下次 IO 如果读取数据在缓存命中了,就不需要等待磁盘的寻址,而是直接返回数据,效率就会快很多。

    2.1.4 BufferedOutputStream

    BufferedOutPutStream 也是 OutputStream 的具体实现类,相比于 FileOutputStream 优化了系统调优,即每次写数据的时候,都会将数据放入缓存区中,等缓存区满了之后,才会一次性写入到磁盘中,大大提高了效率。

    2.2 操作字符流数据

    2.2.1 Reader

    Reader 是实现字符输入流的一种类型,其本身属于一个抽象类,使用时需要使用具体的实现类。Reader 的实现类很多,针对不同的输入设备都可以对应一个实现类,其中针对文件读取的实现类是 FileReader。Reader 的使用方式和 InputStream 相仿。

    示例代码:

    public class Demo2 {
        public static void main(String[] args) throws FileNotFoundException {
            File file = new File("./test.txt");
            StringBuilder sb = new StringBuilder();
            try (Reader reader = new FileReader(file)) {
                while (true) {
                    int read = reader.read();
                    if (read == -1) {
                        break;
                    }
                    sb.append((char) read);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(sb.toString());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.2.2 Writer

    Writer 是实现字符输出流的一种类型,其本身属于一个抽象类,使用时需要使用具体的实现类。Writer 的实现类很多,针对不同的输出设备都可以对应一个实现类,其中针对文件读取的实现类是 FileWriter。Writer 的使用方式和 OutputStream 相仿。

    FileWriter 构造方法:

    构造方法说明
    FileWriter(File file)利用 File 构造对应文件输出流
    FileWriter(String name)利用文件路径构造对应文件输出流
    FileWriter(File file, boolean append)append 表示是否追加数据到文件的末尾,为 true 表示追加,为 false 表示情空之前的内容重新加入
    FileWriter(String name, boolean append)append 表示是否追加数据到文件的末尾,为 true 表示追加,为 false 表示情空之前的内容重新加入

    示例代码:

    public class Demo2 {
        public static void main(String[] args) throws FileNotFoundException {
            File in = new File("./in.txt");
            File out = new File("./out.txt");
            try (Reader reader = new FileReader(in);
                 Writer writer = new FileWriter(out)) {
                while (true) {
                    int read = reader.read();
                    if (read == -1) {
                        break;
                    }
                    writer.write(read);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.2.3 BufferedReader

    BufferedReader 也是 Reader 的具体实现类,相比于 Reader 优化了系统调用,即通俗解释为:将数据保存了缓存区,但是减少磁盘 IO 并不是 BufferedReader 来做的,而是 OS 来做的。OS 根据局部性原理,会预读部分的数据到内存缓存区,这样下次 IO 如果读取数据在缓存命中了,就不需要等待磁盘的寻址,而是直接返回数据,效率就会快很多。

    2.2.4 BufferedWriter

    BufferedWriter 也是 Writer 的具体实现类,相比于 Writer 优化了系统调优,即每次写数据的时候,都会将数据放入缓存区中,等缓存区满了之后,才会一次性写入到磁盘中,大大提高了效率。

    2.3 Scanner 和 PrintWriter

    Java 标准库中提供的 Scanner 和 PrintWriter 类能够像文件中读取文本数据和写入文本数据。

    2.3.1 Scanner

    java.util.Scanner 类常用来从控制台中读取字符串和基本类型的数值。Scanner 可以将输入的值以空白字符分割标记。

    Scanner 的构造方法:

    构造方法说明
    Scanner(Readable source)创建一个 Scanner,从指定的可读资源中扫描标记,包括文件、文件路径、字符串等。
    Scanner(InputStream source)创建一个 Scanner,从指定的字节输入流中扫把标记。

    Scanner 常用方法:

    方法返回值类型说明
    hasNext()boolean如果 Scanner 还要更多的数据可读取,则返回 true
    next()String从 Scanner 中读取下一个标记作为字符串返回
    nextLine()String从 Scanner 中读取一行,以换行符结束
    close()void关闭 Scanner
    • System.in 为系统自带的标准输入流,该流是一直打开并准备提供输入数据。通常,这个流对应于键盘输入或由主机环境或用户指定的另一个输入源。
    • 使用 Scanner 没有必要关闭输入文件,但是关闭能够释放文件占有的资源。

    示例代码:

    public class Demo3 {
    
        public static void main(String[] args) {
            try (Scanner scanner = new Scanner(new File("./test.txt"))) {
                while (scanner.hasNext()) {
                    String s = scanner.next();
                    System.out.println(s);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.3.2 PrintWriter

    java.io.PrintWriter 类可用来创建一个文件并向文本文件中写入数据。通常使用 System.out.println 向控制台输入文本。

    PrintWriter 构造方法:

    构造方法说明
    PrintWriter(Writer out)为指定的字符输入流创建一个 PrintWriter。
    PrintWriter(Writer out, boolean autoFlush)为指定的字符输入流创建一个 PrintWriter,如果 autoFlush 为 true,则 println、printf 或 format 方法将刷新输出缓冲区。
    PrintWriter(OutputStream out)为指定的字节输入流创建一个 PrintWriter。
    PrintWriter(OutputStream out, boolean autoFlush)为指定的字节输入流创建一个 PrintWriter,如果 autoFlush 为 true,则 println、printf 或 format 方法将刷新输出缓冲区。
    PrintWriter(String fileName)为指定的文件路径创建一个 PrintWriter
    PrintWriter(String fileName, String csn)为指定的文件路径创建一个 PrintWriter,并且通过指定的字符集对字符进行编码。
    PrintWriter(File file)为指定的文件对象创建一个 PrintWriter。
    PrintWriter(File file, String scn)为指定的文件对象创建一个 PrintWriter,并且通过指定的字符集对字符进行编码。

    PrintWriter 常用方法:

    方法返回值类型说明
    print(String s)void将字符串写入文件中
    println(String s)void将字符串写入文件中,多打印一个换行
    printf(String s)void将字符串写入文件中,按照指定格式写文件中
    • System.out 为系统自带的 printStream,表示控制台的标准 Java 对象,通过它能够向控制台输入数据。
    • 使用 PrintWriter 必须使用 close 方法关闭文件,或者使用 try-with-resources 自动关闭资源,狗则数据就不能正确地保存在文件中。

    示例代码:

    public class Demo3 {
    
        public static void main(String[] args) {
            try (Scanner scanner = new Scanner(new File("./in.txt"));
                 PrintWriter printWriter = new PrintWriter("./out.txt")) {
                while (scanner.hasNext()) {
                    String s = scanner.next();
                    printWriter.println(s);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    【DaVinci Developer工具实战】02 - 软件设计编辑器
    解析java中的多线程的基本概念
    阿里、腾讯、京东、拼多多智慧农业斗法
    docker
    【STM32】SD卡
    bash while循环和until循环
    VSCode打开 C(嵌入式) 工程的一些记录
    408王道计算机组成原理——数据的运算及大题
    Vscode中注释变成繁体的解决方法
    集群扩容与半同步复制
  • 原文地址:https://blog.csdn.net/weixin_51367845/article/details/126672910