java随机访问文件_Java开发笔记(八十七)随机访问文件的读写

Java的RandomAccessFile类提供了一种高效修改文件的方法,尤其适用于大文件的追加和插入操作。它可以定位到文件任意位置进行读写,避免了全文读取和覆盖原有内容的问题。示例代码展示了如何在文件末尾追加数据和在指定位置插入数据。
摘要由CSDN通过智能技术生成

前面介绍了字符流读写文件的两种方式,包括文件字符流和缓存字符流,但是它们的写操作都存在一个问题:不管是write方法还是append方法,都只能从文件开头写入,而不能追加到文件末尾或者在文件中间某个位置写入。这个问题真不好办,它意味着每次写操作都会覆盖掉原来的文件内容,注意是直接覆盖而非局部修改,可大多数的业务场景需要在原文件基础上追加或者修改的。倘若坚持使用字符流修改文件内容,也不是不可以,那样得把原来的文件内容全部读到某个字符串,再对该字符串进行修改操作,最后把改后的字符串重新写入原文件。这么处理的话,对付小文件倒还凑合,要是遇到超大文件,比如大小达到1G的文件,光光把这1G的数据读到内存就足以让程序崩溃了。因此,通过字符流修改文件并非好办法,不如采用专门的文件修改工具即RandomAccessFile(随机访问文件类),该工具特别适合对文件做各种花式修改。随机文件工具RandomAccessFile提供了seek方法用来定位当前的读写位置,可以很方便地在指定位置写入数据,故而RandomAccessFile经常用于以下几个场合:

1、往大文件末尾追加数据。

2、下载文件时候的断点续传,支持从上次已下载完成的地方中途开始,而不必重头下载整个文件。

创建随机文件对象依然要指定文件路径,同时还要指定该文件的打开方式,下面是创建随机文件对象的代码例子:

// 根据文件路径创建既可读又可写的随机文件对象

String mAppendFileName = "D:/test/random_appendStr.txt";

RandomAccessFile raf = new RandomAccessFile(mAppendFileName, "rw");

上面构造方法的第二个参数值为rw,表示以既可读又可写的模式打开文件。除了常见的rw,模式参数还有其它取值,具体的取值说明如下:

r:以只读方式打开指定文件。如果试图对该文件执行write写入方法,则会抛出异常IOException。

rw:以可读且可写的方式打开指定文件。如果该文件不存在,则尝试创建新文件。

rws:以可读且可写的方式打开指定文件。rws模式的每次write方法都会立即写入文件,它相当于FileWriter;而rw模式先把数据写到缓存,等到缓存满了或者调用close方法关闭文件之时,才将缓存中的数据真正写入文件,它相当于BufferedWriter。

rwd:与rws模式类似。区别在于rwd只更新文件内容,不更新文件的元数据,而rws模式会同时更新文件内容及元数据。所谓元数据保存了文件的基本信息,包括文件类型(是文件还是目录)、文件的创建时间、文件的修改时间、文件的访问权限(是否可读、是否可写、是否可执行)等等。

与字符流工具相比,随机文件工具用起来反而更简单,一个RandomAccessFile就集成了File、FileWriter、FileReader三个工具的基本用法,它的主要方法说明如下:

length:获取指定文件的文件大小。

setLength:设置指定文件的文件大小。

seek:移动指定文件的访问位置。

write:往文件的当前位置写入字节数组。

read:把当前位置之后的文件内容读到字节数组。

close:关闭文件。RandomAccessFile拥有close方法,意味着它支持try-with-resources方式的自动释放资源。

以在文件末尾追加数据为例,使用RandomAccessFile完成的话,先调用seek方法定位到文件末尾,再调用write方法写入字节数组形式的数据。这个追加功能的实现代码如下所示:

private static String mAppendFileName = "D:/test/random_appendStr.txt";

// 往随机文件末尾追加字符串

private static void appendStr() {

// 创建指定路径的随机文件对象(可读写)。try(...)支持在处理完毕后自动关闭随机文件

try (RandomAccessFile raf = new RandomAccessFile(mAppendFileName, "rw")) {

long length = raf.length(); // 获取随机文件的长度(文件大小)

raf.seek(length); // 定位到指定长度的位置

String str = String.format("你好世界%.10f\n", Math.random());

raf.write(str.getBytes()); // 往随机文件写入字节数组

} catch (Exception e) {

e.printStackTrace();

}

}

从上面代码看到,随机文件工具能够直接往文件末尾添加数据,即使原文件有好几个G大小,也丝毫不影响数据追加的效率。

再看一个往文件内部的任意位置插入数据的例子,仍然是先调用seek方法跳到指定位置,再调用write方法写入字节数据。下面的演示代码中,为了确保seek跳转的位置始终落在文件内部,在一开始就调用setLength方法设置文件的固定大小。在任意位置插入数据的详细代码参见如下:

private static String mFixsizeFileName = "D:/test/random_fixsize.txt";

// 往固定大小的随机文件中插入数据

private static void fixSizeInsert() {

// 创建指定路径的随机文件对象(可读写)。try(...)支持在处理完毕后自动关闭随机文件

try (RandomAccessFile raf = new RandomAccessFile(mFixsizeFileName, "rw")) {

raf.setLength(1000); // 设置随机文件的长度(文件大小)

for (int i=0; i<=2 ;i++) {

raf.seek(i*200); // 定位到指定长度的位置

String str = String.format("你好世界%.10f\n", Math.random());

raf.write(str.getBytes()); // 往随机文件写入字节数组

}

} catch (Exception e) {

e.printStackTrace();

}

}

最后瞧瞧随机文件工具的读文件操作,与字符流工具比较,它俩的处理流程大体一致,但在细节上有个区别:随机文件工具的read方法支持一次性读到字节数组,而字符流工具的read方法支持一次性读到字符数组。下面是通过RandomAccessFile读取文件内容的代码例子,可以看到它是以字节为单位读出数据的:

// 读取随机文件的文件内容

private static void readContent() {

// 创建指定路径的随机文件对象(只读)。try(...)支持在处理完毕后自动关闭随机文件

try (RandomAccessFile raf = new RandomAccessFile(mAppendFileName, "r")) {

int length = (int) raf.length(); // 获取随机文件的长度(文件大小)

byte[] bytes = new byte[length]; // 分配长度为文件大小的字节数组

raf.read(bytes); // 把随机文件的文件内容读取到字节数组

String content = new String(bytes); // 把字节数组转成字符串

System.out.println("content="+content);

} catch (Exception e) {

e.printStackTrace();

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值