随机存取文件流RandomAccessFile

RandomAccessFile 声明在java.io包下,但直接继承于java.lang.Object类。并且它实现了DataInput、DataOutput这两个接口,也就意味着这个类既可以读也可以写

RandomAccessFile 类支持 “随机访问” 的方式,程序可以直接跳到文件的任意地方来读、写文件

  • 支持只访问文件的部分内容
  • 可以向已存在的文件后追加内容

RandomAccessFile 对象包含一个记录指针,用以标示当前读写处的位置。 RandomAccessFile 类对象可以自由移动记录指针:

  • long getFilePointer():获取文件记录指针的当前位置
  • void seek(long pos):将文件记录指针定位到 pos 位置

构造器

1
public RandomAccessFile(File file, String mode) 
1
public RandomAccessFile(String name, String mode) 

创建 RandomAccessFile 类实例需要指定一个 mode 参数,该参数指 定 RandomAccessFile 的访问模式:

  • r: 以只读方式打开

  • rw:打开以便读取和写入

  • rwd:打开以便读取和写入;同步文件内容的更新

  • rws:打开以便读取和写入;同步文件内容和元数据的更新

如果模式为只读r。则不会创建文件,而是会去读取一个已经存在的文件, 如果读取的文件不存在则会出现异常。 如果模式为rw读写。如果文件不存在则会去创建文件,如果存在则不会创建。

我们可以用RandomAccessFile这个类,来实现一个多线程断点下载的功能, 用过下载工具的朋友们都知道,下载前都会建立两个临时文件,一个是与 被下载文件大小相同的空文件,另一个是记录文件指针的位置文件,每次 暂停的时候,都会保存上一次的指针,然后断点下载的时候,会继续从上 一次的地方下载,从而实现断点下载或上传的功能,有兴趣的朋友们可以 自己实现下。

image-20200516220845586

image-20200516220927795

读写成功!

创建一个hello.txt

image-20200516221314940

image-20200516221352347

image-20200516221509281

使用随机文件流实现数据的覆盖插入效果。原理将要插入数据的角标后的所有数据都保存起来,然后插入数据。在插入的数据之后追加被保存的数据。

image-20200516222209502

image-20200516222219424

流的基本应用小节

流是用来处理数据的。

处理数据时,一定要先明确数据源,与数据目的地

  • 数据源可以是文件,可以是键盘。

  • 数据目的地可以是文件、显示器或者其他设备。

而流只是在帮助数据进行传输,并对传输的数据进行处理,比如过滤处理、 转换处理等。

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/**
* RandomAccessFile的使用
* 1.RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
* 2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
* <p>
* 3.如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
* 如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
* <p>
* 4. 可以通过相关的操作,实现RandomAccessFile“插入”数据的效果
*/
public class RandomAccessFileTest {

@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();
}
}
}
}

@Test
public void test2() throws IOException {

RandomAccessFile raf1 = new RandomAccessFile("hello.txt", "rw");

raf1.seek(3);//将指针调到角标为3的位置
raf1.write("xyz".getBytes());//

raf1.close();

}

/*
使用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("1111".getBytes());

//将StringBuilder中的数据写入到文件中
raf1.write(builder.toString().getBytes());

raf1.close();

}

}