【JavaSE】文件 IO(操作文件)

文章目录

    • 1. 操作文件系统
      • File 常用属性及方法
        • 1.1 属性
        • 1.2 构造方法
        • 1.3 方法
    • 2. 操作文件内容——数据流
      • 2.1 字节流
      • 2.2 字符流
        • 2.2.1 Reader
        • 2.2.2 Writer

操作系统会将硬件设备和软件资源都抽象为 ”文件“,统一进行管理。大部分情况下,文件指的是硬盘的文件,即对硬盘数据的抽象,因此可以通过文件来操作硬盘。

计算机上的文件通过文件系统来进行组织和管理,操作系统通过目录的结构来组织文件。

文本文件:保存的都是字符串,所有数据都能够在字符集中找到相应的字符(合法的字符)

二进制文件:保存的是二进制数据

1. 操作文件系统

Java 中通过 File 对文件或目录进行抽象的描述

File 常用属性及方法

1.1 属性
类型 字段名 解释
public static final String pathSeparator 依赖于系统的路径分隔符
public static final char pathSeparatorChar 依赖于系统的路径分隔符
1.2 构造方法
签名 解释
File(File parent, String child) 根据父目录+孩子文件路径创建
File(String pathname) 根据文件路径创建
File(String parent, String child) 根据父目录+孩子文件路径创建
1.3 方法
修饰符及返回值类型 签名 解释
String getParent() 返回 File 对象的父目录文件路径
String getName() 返回 File 对象的纯文件名称
String getPath() 返回 File 对象的文件路径
String getAbsolutePath() 返回 File 对象的绝对路径
String getCanonicalPath() 返回 File 对象的修饰过的绝对路径
boolean exists() 判断 File 对象描述的的文件是否真实存在
boolean isDirectory() 判断 File 对象代表的文件是否是一个目录
boolean isFile() 判断 File 对象代表的文件是否是一个普通文件
boolean createNewFile() 根据 File 对象,自动创建一个空文件,成功创建后返回 true
boolean delete() 根据 File 对象,删除该文件,成功删除后返回 true
void deleteOnExit() 根据 File 对象,删除该文件,删除动作在 JVM 运行结束时执行
String[] list() 返回 File 对象代表的目录下的所有文件名
File[] listFiles() 返回 File 对象代表的目录下的所有文件
boolean mkdir() 创建 File 对象代表的目录
boolean mkdirs() 创建 File 对象代表的目录,如果必要,会创建中间目录
boolean renameTo(File dest) 文件重命名(剪切、粘贴)
boolean canRead() 判断用户是否对文件有可读权限
boolean canWrite() 判断用户是否对文件有可写权限

2. 操作文件内容——数据流

标准库中提供的读写文件的流对象,有很多个类,主要分为两种,一种是读取二进制文件的字节流,另一种是读取文本文件的字符流

2.1 字节流

每次读 / 写的最小单位是 ”字节“

基本父类:InputStream, OutputStream

2.2 字符流

每次读 / 写的最小单位是 ”字符“。本质上是对字节流进行了封装。

无论是文本文件还是二进制文件,在硬盘上都是以二进制方式存储的,字符流能自动将文件中相邻的几个字节转换成一个字符(自动查字符集表)

基本父类:Reader, Writer

2.2.1 Reader
Reader reader = new FileReader("D:/test.txt");

方法

返回值 签名 解释
int read() 一次读取一个字符,返回 unicode 编码,若读到文件结束,返回 -1
int read(char cbuf[]) 一次读取多个字符,将参数指定的 cbuf 填充满,返回实际读取到的字符个数,若读到文件结束,返回 -1
int read(char cbuf[], int off, int len) 一次读取多个字符,将参数指定的 cbuf 的从 off 到 len这么长的范围填充满

Java 标准库内部,如果只使用 char,此时使用的字符集就是 unicode(一个汉字 2 个字节),如果使用 String,此时就会自动把每个字符的 unicode 转为 utf8(一个汉字 3 个字节)

public static void main(String[] args) throws IOException {
    Reader reader = new FileReader("D:/test.txt");
    // 一次读一个字符
    while (true) {
        int c = reader.read();
        if (c == -1) {
            break;
        }
        char ch = (char)c;
        System.out.println(ch);
    }
    
    // 一次读取多个字符
    while (true) {
        char[] cbuf = new char[3];
        int n = reader.read(cbuf);
        if (n == -1) {
            break;
        }
        System.out.println("n = " + n);
        for (int i = 0; i < n; i++) {
            System.out.println(cbuf[i]);
        }
    }
    // 释放文件描述符
    reader.close();
}

close():为了释放文件描述符。PCB 中的文件描述符表(顺序表),记录了当前进程所持有的硬盘资源,当前进程每打开一个文件,就会在这个表中添加元素,但数组的长度是存在上限的,如果代码只打开文件而不关闭,这个表中的元素越来越多,最终会占满,后续再尝试打开文件就会报错

按照上面的方式来写的话,如果 close 之前的代码执行过程中出现异常,那么 close 便不会执行到,这里使用 try…catch…来解决,这样的话,无论 try 中的代码是否执行出现异常,都能保证 finally 中的 close 的执行

// 1. try…catch
try {
    // 一次读取多个字符
    while (true) {
        char[] cbuf = new char[3];
        int n = reader.read(cbuf);
        if (n == -1) {
            break;
        }
        System.out.println("n = " + n);
        for (int i = 0; i < n; i++) {
            System.out.println(cbuf[i]);
        }
    }
} finally {
    // 释放文件描述符
    reader.close();
}

// 2. try with resources
// 在 try 代码块结束时自动调用 reader 的 close 方法
// 写到 () 中的对象必须要实现 closeable 接口
try(Reader reader = new FileReader(("d:/123.txt"))) {
    while (true) {
        char[] cbuf = new char[3];
        int n = reader.read(cbuf);
        if (n == -1) {
            break;
        }
        System.out.println("n = " + n);
        for (int i = 0; i < n; i++) {
            System.out.println(cbuf[i]);
        }
    }
}
2.2.2 Writer
返回值 签名 解释
void write(int c) 一次写一个字符
void write(String str) 一次写多个字符
void write(char[] cbuf) 一次写多个字符(字符数组)
void write(String str, int off, int len) 一次写一个字符串(从 off 开始 len 长度)
void write(char[] cbuf, int off, int len) 一次写一个字符数组(从 off 开始 len 长度)
// FileWriter 构造方法的第二个参数表示是否追加写入
try (Writer writer = new FileWriter("d:/123.txt", true)) {
    writer.write("hello");
} catch (IOException e) {
    throw new RuntimeException(e);
}

字节流转字符流

  1. 读数据
try (InputStream inputStream = new FileInputStream("d:/123.txt")) {
    Scanner scanner = new Scanner(inputStream);
    String s = scanner.next();
    System.out.println(s);
} catch (IOException e) {
    e.printStackTrace();
}
  1. 写数据
try (OutputStream outputStream = new FileOutputStream("d:/123.txt")) {
    // 字节流转字符流
    PrintWriter writer = new PrintWriter(outputStream);
    // PrintWriter 在写入的时候,并非直接写硬盘,为了效率,先将数据写入到一个由内存构成的“缓冲区”中
    // 如果还没来得及将缓冲区中的数据写入硬盘,进程就结束了,那么缓冲区的数据就丢失了
    // 解决办法:在合适的时机使用 flush 方法刷新缓冲区
    writer.printf("123");
    writer.flush();
} catch (IOException e) {
    e.printStackTrace();
}

你可能感兴趣的:(JavaSE,java,文件操作,文件IO)