Java开发笔记(八十七)随机访问文件的读写
前面介绍了字符流读写文件的两种方式,包括文件字符流和缓存字符流,但是它们的写操作都存在一个问题:不管是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();
}
}
更多Java技术文章参见《Java开发笔记(序)章节目录》
Java开发笔记(八十七)随机访问文件的读写的更多相关文章
- Java开发笔记(九十二)文件通道的基本用法
前面介绍的各色流式IO在功能方面着实强大,处理文件的时候该具备的操作应有尽有,可流式IO在性能方面不尽如人意,它的设计原理使得实际运行效率偏低,为此从Java4开始增加了NIO技术,通过全新的架构体系 ...
- Java开发笔记(九十四)文件通道的性能优势
前面介绍了字节缓存的一堆概念,可能有的朋友还来不及消化,虽然文件通道的用法比起传统I/O有所简化,可是平白多了个操控繁琐的字节缓存,分明比较传统I/O更加复杂了.尽管字节缓存享有缓存方面的性能优势,但 ...
- Java I/O---RandomAccessFile类(随机访问文件的读取和写入)
1.JDK API中RandomAccessFile类的描述 此类的实例支持对随机访问文件的读取和写入.随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组.存在指向该隐含数组的光标或索引 ...
- Java开发笔记(九十)对象序列化及其读写
有些时候,开发者想把程序运行过程中的数据临时保存到文件,可是前面介绍的字符流和字节流,要么用来读写文本字符串,要么用来读写字节数组,并不能直接保存某个对象信息,因为对象里面包括成员属性和成员方法,单就 ...
- Java开发笔记(十七)各得其所的多路分支
前面提到条件语句的标准格式为“if (条件) { /* 条件成立时的操作代码 */ } else { /* 条件不成立时的操作代码 */ }”,乍看之下仿佛只有两个分支,一个是条件成立时的分支,另一个 ...
- Java开发笔记(序)章节目录
现将本博客的Java学习文章整理成以下笔记目录,方便查阅. 第一章 初识JavaJava开发笔记(一)第一个Java程序Java开发笔记(二)Java工程的帝国区划Java开发笔记(三)Java帝国的 ...
- Java开发笔记(八十八)文件字节I/O流
前面介绍了如何使用字符流读写文件,并指出字符流工具的处理局限,进而给出随机文件工具加以改进.随机文件工具除了支持访问文件内部的任意位置,更关键的一点是通过字节数组读写文件数据,采取字节方式比起字符方式 ...
- Java开发笔记(八十六)通过缓冲区读写文件
前面介绍了利用文件写入器和文件读取器来读写文件,因为FileWriter与FileReader读写的数据以字符为单位,所以这种读写文件的方式被称作“字符流I/O”,其中字母I代表输入Input,字母O ...
- Java开发笔记(八十四)文件与目录的管理
程序除了处理内存中的数据结构,还要操作磁盘上的各类文件,这里的磁盘是个统称,泛指可以持久保留数据的存储介质,包括但不限于:插在软驱中的软盘.固定在机箱中的硬盘.插在光驱中的光盘.插在USB接口上的U盘 ...
随机推荐
- 前端学习笔记之CSS选择器
阅读目录 一 基本选择器 二 后代选择器.子元素选择器 三 兄弟选择器 四 交集选择器与并集选择器 五 序列选择器 六 属性选择器 七 伪类选择器 八 伪元素选择器 九 CSS三大特性 一 基本选择器 ...
- 异步处理,Event Souring,事务补偿,实现最终一致性和服务的弹性和批处理
这段时间一直学习极客时间皓哥的分布式架构,关于异步处理有一些感想用sketch做了一个图,展示上直观一些,和大家交流下
- gulp、browsersync代理跨域
//gulpfile.js "use strict"; const gulp = require("gulp"), newer = require(" ...
- java游戏开发杂谈 - 事件处理
大家都知道,游戏需要跟玩家交互,需要接收玩家的鼠标.键盘发出的命令,比如在地图上点击一下,人物就自动寻路走过去:键盘上按下某个键,就弹出一个背包界面. 这些逻辑是怎么处理的呢? 大家先不用深究太详细的 ...
- 我的Lambda的学习笔记
前述 Lambda表达式是 Java 8 的新特性.许多语言都有 Lambda 的特性. 因此使用的 Java 环境一定要 8 以上的环境. Lambda 到底什么是 Lambda 表达式呢? Lam ...
- POLARDB · 最佳实践 · POLARDB不得不知道的秘密(二)
前言 POLARDB For MySQL(下文简称POLARDB)目前是阿里云数据库团队主推的关系型数据库.线上已经有很多企业用户在使用并且稳定运行了很久.当然,由于POLARDB是为云上环境专门打造 ...
- 动态路由协议(RIP)
虽然静态路由在某些时刻很有用,但是必须手工配置每条路由条目,对于大中型的网络或拓补经常发生变化的清空,配置和维护静态路由的工作量就变得非常繁重,而且不小心还容易出错,因此就需要一种不需要手工配置的路由 ...
- HTML入门知识汇总
1. HTML认识 1.1 什么是HTML HTML是描述(制作)网页的语言,指的是超文本标记语言(Hyper Text Markup Language). 超文本:就是指页面内可以包含图片.链接.甚 ...
- 全新定义!免费开源ERP平台如何玩转工业互联网
简述 IoT Box通过Wifi.蓝牙.USB.网线等方式连接设备.IoT再通过互联网连接到Odoo服务器 Odoo的各种应用通过IoT操作各种设备.例如,PoS应用通过IoT操作小票打印机.银行刷卡 ...
- 安卓开发笔记(二十二):读取本地(内置)html文件并实现和Javascript交互
实际上我们通常是使用WebView控件对本地html进行读取,这样就可以体会类似web app和安卓原生混合开发的乐趣了.在读取本地html并展示在前台的时候,并不需要在Androidmenifast ...