理论
Java除了File类之外,还提供了专门处理文件的类,即RandomAccessFile(随机访问文件)类。
该类是Java语言中功能最为丰富的文件访问类,它提供了众多的文件访问方法。RandomAccessFile类支持“随机访问”方式,这里“随机”是指可以跳转到文件的任意位置处读写数据。在访问一个文件的时候,不必把文件从头读到尾,而是希望像访问一个数据库一样“随心所欲”地访问一个文件的某个部分,这时使用RandomAccessFile类就是最佳选择。
RandomAccessFile对象类有个位置指示器,指向当前读写处的位置,当前读写n个字节后,文件指示器将指向这n个字节后面的下一个字节处。
刚打开文件时,文件指示器指向文件的开头处,可以移动文件指示器到新的位置,随后的读写操作将从新的位置开始。
RandomAccessFile类在数据等长记录格式文件的随机(相对顺序而言)读取时有很大的优势,但该类仅限于操作文件,不能访问其他的I/O设备,如网络、内存映像等。
RandomAccessFile类的构造方法如下所示:
//创建随机存储文件流,文件属性由参数File对象指定
RandomAccessFile(File file , String mode)
//创建随机存储文件流,文件名由参数name指定
RandomAccessFile(String name , String mode)
这两个构造方法均涉及到一个String类型的参数mode,它决定随机存储文件流的操作模式,其中mode值及对应的含义如下:
- “r”:以只读的方式打开,调用该对象的任何write(写)方法都会导致IOException异常
- “rw”:以读、写方式打开,支持文件的读取或写入。若文件不存在,则创建之。
- “rws”:以读、写方式打开,与“rw”不同的是,还要对文件内容的每次更新都同步更新到潜在的存储设备中去。这里的“s”表示synchronous(同步)的意思
- “rwd”:以读、写方式打开,与“rw”不同的是,还要对文件内容的每次更新都同步更新到潜在的存储设备中去。使用“rwd”模式仅要求将文件的内容更新到存储设备中,而使用“rws”模式除了更新文件的内容,还要更新文件的元数据(metadata),因此至少要求1次低级别的I/O操作
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
public class RandomFileTest {
private static final String filePath = "C:\\Users\\NineSun\\Desktop\\employee.txt";
public static void main(String[] args) throws Exception {
Employee e1 = new Employee("zhangsan", 23);
Employee e2 = new Employee("lisi", 24);
Employee e3 = new Employee("wangwu", 25);
RandomAccessFile ra = new RandomAccessFile(filePath, "rw");
ra.write(e1.name.getBytes(StandardCharsets.UTF_8));//防止写入文件乱码
ra.writeInt(e1.age);
ra.write(e2.name.getBytes());
ra.writeInt(e2.age);
ra.write(e3.name.getBytes());
ra.writeInt(e3.age);
ra.close();
RandomAccessFile raf = new RandomAccessFile(filePath, "r");
int len = 8;
raf.skipBytes(12);//跳过第一个员工的信息,其姓名8字节,年龄4字节
System.out.println("第二个员工信息:");
String str = "";
for (int i = 0; i < len; i++) {
str = str + (char) raf.readByte();
}
System.out.println("name:" + str);
System.out.println("age:" + raf.readInt());
System.out.println("第一个员工信息:");
raf.seek(0);//将文件指针移动到文件开始位置
str = "";
for (int i = 0; i < len; i++) {
str = str + (char) raf.readByte();
}
System.out.println("name:" + str);
System.out.println("age:" + raf.readInt());
System.out.println("第三个员工信息:");
raf.skipBytes(12);//跳过第二个员工的信息
str = "";
for (int i = 0; i < len; i++) {
str = str + (char) raf.readByte();
}
System.out.println("name:" + str);
System.out.println("age:" + raf.readInt());
raf.close();
}
}
class Employee {
String name;
int age;
final static int LEN = 8;
public Employee(String name, int age) {
if (name.length() > LEN) {
name = name.substring(0, 8);
} else {
while (name.length() < LEN) {
name = name + "\u0000";
}
this.name = name;
this.age = age;
}
}
样例
public void writeByteDataToFile(byte[] fileData, File tempFile,FileUploadMetadataBO fileUploadMetadata) {
RandomAccessFile raf;
try {
raf = new RandomAccessFile(tempFile, "rw");
//这个必须与前端设定的值一致
long chunkSize = Objects.isNull(fileUploadMetadata.getChunkSize()) ? uploadProperties.getDefaultChunkSize() * 1024 * 1024
: fileUploadMetadata.getChunkSize();
// 这里的getChunk(),是从0开始的
long offset = chunkSize * fileUploadMetadata.getChunk();
//定位到该分片的偏移量
raf.seek(offset);
//写入该分片数据
raf.write(fileData);
// TODO 检查
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}