Java IO流系列⑧ -- 随机存取文件流(RandomAccessFile类)
RandomAccessFile类概述
RandomAccessFile 声明在java.io包下,但直接继承于java.lang.Object类。并且它实现了DataInput、DataOutput这两个接口,也就意味着这个类既可以读也可以写。
RandomAccessFile 类支持 “随机访问” 的方式,程序可以直接跳到文件的任意地方来读、写文件。他有一个特殊点就是在他写入文件时,他会对指针所处位置的内容进行覆盖(区别于直接整个文件覆盖,和尾部追加)。
也就是说,如果我要在一个已经存在的文件中写入“abc”,会出现如下情况(假设指针处于开头):
写入前:123456
写入后:abc456
RandomAccessFile 类其底层其实是将文件方法放在一个大的Byte型数组中进行操作。
RandomAccessFile 对象包含一个记录指针,用以标示当前读写处的位置。
RandomAccessFile 类对象可以自由移动记录指针:
- long getFilePointer():获取文件记录指针的当前位置
- void seek(long pos):将文件记录指针定位到 pos 位置
构造器:
- public RandomAccessFile(File file, String mode)
- public RandomAccessFile(String name, String mode)
创建 RandomAccessFile 类实例需要指定一个 mode 参数,该参数指定 RandomAccessFile 的访问模式:
- r: 以只读方式打开
- rw:打开以便读取和写入
- rwd:打开以便读取和写入;同步文件内容的更新
- rws:打开以便读取和写入;同步文件内容和元数据的更新
注意:如果模式为只读r。则不会创建文件,而是会去读取一个已经存在的文件,如果读取的文件不存在则会出现异常。 如果模式为rw读写。如果文件不存在则会去创建文件,如果存在则不会创建。没有w只写模式。
应用:我们可以用RandomAccessFile这个类,来实现一个多线程断点下载的功能,用过下载工具的朋友们都知道,下载前都会建立两个临时文件,一个是与被下载文件大小相同的空文件,另一个是记录文件指针的位置文件,每次暂停的时候,都会保存上一次的指针,然后断点下载的时候,会继续从上。一次的地方下载,从而实现断点下载或上传的功能
用RandomAccessFile类实现数据的读写操作
非文本文件
@Test
public void test1() {
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try {
//1.
raf1 = new RandomAccessFile(new File("爱情与友情.jpg"),"r");
raf2 = new RandomAccessFile(new File("爱情与友情1.jpg"),"rw");
//2.
byte[] buffer = new byte[1024];
int len;
while((len = raf1.read(buffer)) != -1){
raf2.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.
if(raf1 != null){
try {
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(raf2 != null){
try {
raf2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
文本文件
@Test
public void test2() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
raf1.seek(3);//将指针调到角标为3的位置
raf1.write("xyz".getBytes());//
raf1.close();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
注意:
①以上代码同样省略了异常处理
②RandomAccessFile类的write方法只能传入字节或字节型数组。
③有人可能有疑问我明明写入的字节为什么打开显示的却是字符?这是因为在常用编辑器中打开时会自动帮你将字节转化为字符显示。
例:我如果用write()方法向文件中写入97,那么在打开文件后会显示什么?
答案:a
解释:
97的ASCII值为97。首先,97转成二进制,1100001,交给虚拟机-操作系统调用方法写入到你这个构造方法指定的位置。由于常用编辑器会在打开的时候,将字节转换为字符显示,1-127之间的会查询ASCII码表,会显示为a,其它值则查询系统默认的字符集,如果是中文,则查询gbk字符集。
如果你要写入97,可以将97转换为String类型,调用getbytes()方法得到一个数组,写入就行。如:XXX.write(“97”.getBytes())
使用RandomAccessFile实现数据的插入
基本思路:
将要插入地方的后面的数据存储起来,把指针回调到插入位置(因为存储数据的时候指针肯定是会移动的),插入内容后,再将存储好的数据进行尾部添加。
代码实现:
@Test
public void test3() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
raf1.seek(3);//将指针调到角标为3的位置
//保存指针3后面的所有数据到StringBuilder中
StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
byte[] buffer = new byte[20];
int len;
while((len = raf1.read(buffer)) != -1){
builder.append(new String(buffer,0,len)) ;
}
//调回指针,写入“xyz”
raf1.seek(3);
raf1.write("xyz".getBytes());
//将StringBuilder中的数据写入到文件中
raf1.write(builder.toString().getBytes());
raf1.close();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
注意:
①以上代码同样省略了异常处理
②可以将StringBuilder替换为ByteArrayOutputStream进行数据存储
文章来源: blog.csdn.net,作者:十八岁讨厌编程,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/zyb18507175502/article/details/122504061
- 点赞
- 收藏
- 关注作者
评论(0)