RandomAccessFile
是 Java 中提供的一个类,用于在文件中进行随机访问读写操作。它允许在文件的任意位置进行读写,可以用于实现断点续传和分片下载等功能。
- RandomAccessFile(String name, String mode)
- RandomAccessFile(File file, String mode)
name 或 file:文件的路径或 File 对象。
mode:文件的访问模式(r:只读、rw:读写)
常用方法
long length():返回文件的长度(字节数)。
void setLength(long newLength):设置文件长度。
long getFilePointer():返回当前文件指针的位置。
void seek(long pos):将文件指针设置到指定位置。
int read():读取一个字节,返回字节值或 -1(文件末尾)。
int read(byte[] b, int off, int len):读取字节到数组,返回读取字节数。
void write(int b):写入一个字节。
void write(byte[] b, int off, int len):写入字节数组。
void close():关闭文件并释放资源
使用示例
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileExample {
public static void main(String[] args) {
File file = new File("example.txt");
try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
// 写入数据
raf.write("Hello, World!".getBytes());
// 获取文件长度
long fileLength = raf.length();
System.out.println("File Length: " + fileLength);
// 移动文件指针到开头
raf.seek(0);
// 读取数据
byte[] buffer = new byte[(int) fileLength];
raf.read(buffer);
// 打印读取的数据
System.out.println("Read Content: " + new String(buffer));
// 在文件末尾追加数据
raf.seek(fileLength);
raf.write(" Goodbye!".getBytes());
// 再次读取整个文件
raf.seek(0);
byte[] newBuffer = new byte[(int) raf.length()];
raf.read(newBuffer);
System.out.println("Updated Content: " + new String(newBuffer));
} catch (IOException e) {
e.printStackTrace();
}
}
}
断点续传
断点续传是指在下载中断后,继续从上次中断的地方开始下载。RandomAccessFile
可以通过设置文件指针来实现这一功能。
实现步骤
- 记录下载进度:每次下载时记录已下载的字节数。
- 恢复下载:断点续传时,打开文件并将指针移动到上次下载结束的位置。
- 继续下载:从文件指针位置开始继续写入数据。
示例代码
public void resumeDownload(String fileURL, String localFilePath, int startByte) throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL(fileURL).openConnection();
connection.setRequestProperty("Range", "bytes=" + startByte + "-");
try (InputStream inputStream = connection.getInputStream();
RandomAccessFile raf = new RandomAccessFile(localFilePath, "rw")) {
raf.seek(startByte);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
raf.write(buffer, 0, bytesRead);
}
}
}
分片处理
分片处理是一种将大文件分成多个小块并行下载的技术,利用 RandomAccessFile
可以在不同位置写入数据,实现分片下载。
实现步骤
- 计算分片大小:根据文件总大小和线程数计算每个分片的大小。
- 多线程下载:为每个分片启动一个线程,设置文件指针到分片起始位置。
- 合并文件:下载完成后,所有分片自动合并到一个文件中。
示例代码
public void downloadFileWithChunks(String fileURL, String localFilePath, int threadCount) throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL(fileURL).openConnection();
int fileSize = connection.getContentLength();
connection.disconnect();
File file = new File(localFilePath);
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.setLength(fileSize);
raf.close();
int chunkSize = fileSize / threadCount;
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
for (int i = 0; i < threadCount; i++) {
int startByte = i * chunkSize;
int endByte = (i == threadCount - 1) ? fileSize : startByte + chunkSize - 1;
executor.execute(new DownloadChunk(fileURL, localFilePath, startByte, endByte));
}
executor.shutdown();
while (!executor.isTerminated()) {
// 等待所有线程完成
}
System.out.println("Download completed successfully!");
}
static class DownloadChunk implements Runnable {
private final String fileURL;
private final String localFilePath;
private final int startByte;
private final int endByte;
public DownloadChunk(String fileURL, String localFilePath, int startByte, int endByte) {
this.fileURL = fileURL;
this.localFilePath = localFilePath;
this.startByte = startByte;
this.endByte = endByte;
}
@Override
public void run() {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(fileURL).openConnection();
connection.setRequestProperty("Range", "bytes=" + startByte + "-" + endByte);
InputStream inputStream = connection.getInputStream();
RandomAccessFile raf = new RandomAccessFile(localFilePath, "rw");
raf.seek(startByte);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
raf.write(buffer, 0, bytesRead);
}
raf.close();
inputStream.close();
connection.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意事项
- 服务器支持:确保服务器支持 HTTP Range 请求。
- 资源管理:使用
try-with-resources
确保文件流正确关闭。 - 错误处理:在实际应用中需要处理网络异常、文件权限等问题。
- 线程数选择:根据网络和服务器条件合理选择线程数。
通过以上方法,RandomAccessFile
可以有效地用于实现复杂的文件操作,如断点续传和分片下载。