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


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

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

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

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

1. 操作文件系统

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

File 常用属性及方法

1.1 属性
类型字段名解释
public static final StringpathSeparator依赖于系统的路径分隔符
public static final charpathSeparatorChar依赖于系统的路径分隔符
1.2 构造方法
签名解释
File(File parent, String child)根据父目录+孩子文件路径创建
File(String pathname)根据文件路径创建
File(String parent, String child)根据父目录+孩子文件路径创建
1.3 方法
修饰符及返回值类型签名解释
StringgetParent()返回 File 对象的父目录文件路径
StringgetName()返回 File 对象的纯文件名称
StringgetPath()返回 File 对象的文件路径
StringgetAbsolutePath()返回 File 对象的绝对路径
StringgetCanonicalPath()返回 File 对象的修饰过的绝对路径
booleanexists()判断 File 对象描述的的文件是否真实存在
booleanisDirectory()判断 File 对象代表的文件是否是一个目录
booleanisFile()判断 File 对象代表的文件是否是一个普通文件
booleancreateNewFile()根据 File 对象,自动创建一个空文件,成功创建后返回 true
booleandelete()根据 File 对象,删除该文件,成功删除后返回 true
voiddeleteOnExit()根据 File 对象,删除该文件,删除动作在 JVM 运行结束时执行
String[]list()返回 File 对象代表的目录下的所有文件名
File[]listFiles()返回 File 对象代表的目录下的所有文件
booleanmkdir()创建 File 对象代表的目录
booleanmkdirs()创建 File 对象代表的目录,如果必要,会创建中间目录
booleanrenameTo(File dest)文件重命名(剪切、粘贴)
booleancanRead()判断用户是否对文件有可读权限
booleancanWrite()判断用户是否对文件有可写权限

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

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

2.1 字节流

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

基本父类:InputStream, OutputStream

2.2 字符流

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

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

基本父类:Reader, Writer

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

方法

返回值签名解释
intread()一次读取一个字符,返回 unicode 编码,若读到文件结束,返回 -1
intread(char cbuf[])一次读取多个字符,将参数指定的 cbuf 填充满,返回实际读取到的字符个数,若读到文件结束,返回 -1
intread(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
返回值签名解释
voidwrite(int c)一次写一个字符
voidwrite(String str)一次写多个字符
voidwrite(char[] cbuf)一次写多个字符(字符数组)
voidwrite(String str, int off, int len)一次写一个字符串(从 off 开始 len 长度)
voidwrite(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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Undefined name!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值