RandomAccessFile既可以读取文件内容,也可以向文件输出数据。同时,RandomAccessFile支持“随机访问”的方式,程序快可以直接跳转到文件的任意地方来读写数据。
由于RandomAccessFile可以自由访问文件的任意位置,所以如果需要访问文件的部分内容,而不是把文件从头读到尾,使用RandomAccessFile将是更好的选择。
与OutputStream、Writer等输出流不同的是,RandomAccessFile允许自由定义文件记录指针,RandomAccessFile可以不从开始的地方开始输出,因此RandomAccessFile可以向已存在的文件后追加内容。如果程序需要向已存在的文件后追加内容,则应该使用RandomAccessFile。
RandomAccessFile的方法虽然多,但它有一个最大的局限,就是只能读写文件,不能读写其他IO节点。
RandomAccessFile的一个重要使用场景就是网络请求中的多线程下载及断点续传。
RandomAccessFile类有两个构造函数,其实这两个构造函数基本相同,只不过是指定文件的形式不同:一个需要使用String参数来指定文件名,一个使用File参数来指定文件本身。除此之外,创建RandomAccessFile对象时还需要指定一个mode参数,该参数指定RandomAccessFile的访问模式,一共有4种模式。
- “r” : 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
- “rw”: 打开以便读取和写入。
- “rws”: 打开以便读取和写入。相对于 “rw”,“rws” 还要求对“文件的内容”或“元数据”的每个更新都同步写入到基础存储设备。
- “rwd” : 打开以便读取和写入,相对于 “rw”,“rwd” 还要求对“文件的内容”的每个更新都同步写入到基础存储设备。
注意:当RandomAccessFile向指定文件中插入内容时,将会覆盖掉原有内容。如果不想覆盖掉,则需要将原有内容先读取出来,然后先把插入内容插入后再把原有内容追加到插入内容后。
示例public class DemoTest{
/**
* 在目标文件的任意位置插入内容
* 1、将插入点之后的内容写到临时文件中
* 2、将待插入的内容插入到插入点位置
* 3、将临时文件中的内容追加到目标文件的结尾
*
* @param fileName 待插入内容的内容
* @param pos 插入位置
* @param content 插入内容
* @throws IOException
*/
public static void fileRandInsert(String fileName, int pos, String content) {
File file = new File(fileName);
RandomAccessFile raf = null;
FileOutputStream fos = null;
FileInputStream fis = null;
try {
raf = new RandomAccessFile(file, "rw");
//临时文件
File tmp = File.createTempFile("hahaha", "tmp");
fos = new FileOutputStream(tmp);
fis = new FileInputStream(tmp);
raf.seek(pos);
int len = -1;
byte[] buf = new byte[2];
while ((len = raf.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.flush();
raf.seek(pos);
//将字符串转换成字节数组
byte[] bytes = content.getBytes();
raf.write(bytes);
//将文件指针定位到追加后的位置
raf.seek(pos + bytes.length);
while ((len = fis.read(buf)) != -1) {
raf.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//释放资源
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (raf != null) {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
public static void main(String[] args) throws Exception {
int insertPosition = 11;
String content = "中国人民";
String fileName = "abcd";
fileRandInsert(fileName, insertPosition, content);
}
}
核心方法说明:
- long getFilePointer( ):返回文件记录指针的当前位置
- void seek(long pos ):将文件指针定位到pos位置