Java食用备忘
第一章 RandomAccessFile类详解
文章目录
前言
RandomAccessFile 是 Java IO 体系中一个特殊的文件操作类,它区别于普通的流(InputStream/OutputStream、Reader/Writer),核心优势在于支持随机访问文件内容,可自由定位文件读写位置,兼具读和写的功能。
一、核心特性
- 双向操作能力:同时实现了 DataInput 和 DataOutput 接口,无需分别创建输入流和输出流,可在同一个对象上完成文件的读取与写入操作。
- 随机访问核心:通过文件指针(file pointer)控制读写位置,文件指针代表当前将要读写的字节偏移量(初始为 0,对应文件开头),支持手动移动指针,实现非顺序的随机读写。
- 独立于普通流体系:不继承 InputStream 或 OutputStream,是 Java IO 中单独的类,仅用于操作文件,不支持其他 IO 数据源(如网络流)。
二、关键构造方法
RandomAccessFile 的构造方法需指定文件路径 / 文件对象,以及访问模式,核心构造方法如下:
| 构造方法 | 说明 |
|---|---|
| RandomAccessFile(File file, String mode) | 以指定 File 对象和访问模式创建实例 |
| RandomAccessFile(String name, String mode) | 以指定文件路径字符串和访问模式创建实例 |
核心访问模式(重点)
常用的两种核心模式,决定了文件的操作权限:
- “r”:只读模式
- 仅允许读取文件内容,无法执行写入操作。
- 如果指定的文件不存在,会抛出 FileNotFoundException。
- “rw”:读写模式
- 允许同时进行文件的读取和写入操作。
- 如果指定的文件不存在,会自动创建该文件;如果文件已存在,写入操作不会清空原有内容(仅覆盖对应位置的字节)。
- 补充模式:“rwd”、“rws”(基于 rw 扩展,保证写入数据的持久性,多用于高可靠性场景,日常开发较少使用)。
三、随机访问的核心方法(文件指针控制)
文件指针的移动和定位是 RandomAccessFile 实现随机访问的关键,核心方法如下:
- long getFilePointer()
- 功能:获取当前文件指针的位置(字节偏移量)。
- 返回值:long 类型,代表当前指针距离文件开头的字节数。
- void seek(long pos)
- 功能:将文件指针移动到指定的绝对位置(核心方法)。
- 参数 pos:目标字节偏移量(pos >= 0),可以定位到文件任意有效位置(包括文件末尾,用于追加写入)。
- int skipBytes(int n)
- 功能:将文件指针向前(向后不支持)跳过指定的字节数。
- 返回值:实际跳过的字节数(可能小于 n,如到达文件末尾时)。
四、核心读写方法
由于实现了 DataInput 和 DataOutput 接口,RandomAccessFile 提供了丰富的类型安全读写方法,常用核心方法如下:
1. 读取方法(对应 DataInput 接口)
| 方法 | 说明 |
|---|---|
| int read() | 读取单个字节,返回字节值(0-255),到达文件末尾返回 -1 |
| int read(byte[] b) | 读取字节到数组 b 中,返回实际读取的字节数 |
| byte readByte() | 读取单个字节(支持负数,范围 -128~127) |
| int readInt() | 读取 4 个字节,转换为 int 类型 |
| long readLong() | 读取 8 个字节,转换为 long 类型 |
| String readUTF() | 读取 UTF-8 编码的字符串 |
2. 写入方法(对应 DataOutput 接口)
| 方法 | 说明 |
|---|---|
| void write(int b) | 写入单个字节(仅保留低 8 位) |
| void write(byte[] b) | 写入字节数组 b 中的所有内容 |
| void writeByte(int b) | 写入单个字节 |
| void writeInt(int v) | 写入 4 个字节的 int 类型值 |
| void writeLong(long v) | 写入 8 个字节的 long 类型值 |
| void writeUTF(String s) | 写入 UTF-8 编码的字符串 |
五、典型使用场景
- 文件分段读写:如大文件分片上传 / 下载,通过 seek() 定位到分片的起始位置,读取或写入指定大小的字节数据。
- 文件内容更新 / 覆盖:无需读取整个文件,直接定位到需要修改的位置,覆盖写入新内容(例如修改配置文件中的某个参数、更新日志文件的指定条目)。
- 文件追加写入:先通过 length() 方法获取文件总长度,再用 seek(file.length()) 将指针移到文件末尾,执行写入操作,实现追加效果。
- 随机读取文件内容:如读取文件中指定位置的记录(如数据库备份文件、固定格式的日志文件),无需顺序遍历。
六、使用示例(核心功能演示)
示例 1:读写文件 + 指针定位
import java.io.RandomAccessFile;
import java.io.IOException;
public class RandomAccessFileDemo {
public static void main(String[] args) {
// 定义文件路径
String filePath = "test.txt";
try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
// 1. 写入数据(初始指针在 0 位置)
raf.writeUTF("Hello RandomAccessFile");
raf.writeInt(100);
raf.writeLong(20260105L);
// 2. 获取当前指针位置
long currentPos = raf.getFilePointer();
System.out.println("写入后指针位置:" + currentPos);
// 3. 移动指针到文件开头(pos = 0)
raf.seek(0);
// 4. 读取数据(按写入顺序读取,类型需对应)
String str = raf.readUTF();
int num = raf.readInt();
long date = raf.readLong();
System.out.println("读取的字符串:" + str);
System.out.println("读取的int值:" + num);
System.out.println("读取的long值:" + date);
// 5. 定位到指定位置,覆盖写入
raf.seek(str.length() + 2); // UTF字符串会先写入2个字节的长度标识,故偏移量需预留
raf.writeUTF("Java");
} catch (IOException e) {
e.printStackTrace();
}
}
}
示例 2:文件追加写入
import java.io.RandomAccessFile;
import java.io.IOException;
public class RandomAccessFileAppend {
public static void main(String[] args) {
String filePath = "append.txt";
try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
// 1. 将指针移到文件末尾
raf.seek(raf.length());
// 2. 追加写入数据
raf.writeUTF("这是追加的内容");
raf.writeByte('\n'); // 换行符
System.out.println("数据追加成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
七、注意事项
- 资源释放:RandomAccessFile 实现了 AutoCloseable 接口,推荐使用 try-with-resources 语法自动关闭资源,避免文件句柄泄露。
- 类型匹配:读取数据时,必须与写入时的类型顺序一致(如先写 writeUTF(),后写 writeInt(),读取时需先 readUTF(),后 readInt()),否则会出现数据错乱或 EOFException。
- 指针越界:seek() 方法的参数 pos 不能为负数,若超过文件长度,写入时会填充空白字节,读取时会抛出 EOFException。
- 编码问题:readUTF() 和 writeUTF() 使用的是 Java 特定的 UTF-8 编码(与标准 UTF-8 略有差异),若读取非该方式写入的字符串,会出现乱码。
总结
- RandomAccessFile 核心优势是随机访问(通过 seek() 控制文件指针),兼具读写能力,不依赖普通 IO 流体系。
- 核心访问模式:“r”(只读)、“rw”(读写,文件不存在自动创建)。
- 关键方法:getFilePointer()(获取指针)、seek()(定位指针)、readXXX()(类型读取)、writeXXX()(类型写入)。
- 典型场景:文件分段操作、内容更新、追加写入、随机读取,适合处理固定格式或大文件。

1214

被折叠的 条评论
为什么被折叠?



