今儿翻阅jdk源码的时候,无意间发现了RandomAccessFile这个类,从来没见过,也没使用过,带着好奇心,我决定深入了解一下这个类的意义和使用方法。
从字面意思来看这个:随机 通行 文件
其实个人感觉就是:
一款功能较丰富的文本编辑工具
话不多说,让我们先一探究竟,初步了解这个类的设计理念
目录
一、api的研究
曾经的我们如何处理文本
以前我们要处理一个文件会怎么做?是不是如下图所示:
上面是读取文件的方式,写文件也一样,我们需要使用输出流,如下图所示:
ok 看到这里想必大家都会发现,我对一个文件的读写操作需要new两个类,分别是读流和写流,并且他们的方法并不多
RandomAccessFile类帮我们处理文本
首先观察构造器:
可以发现这里定义了四种模式:R RW RWD RWS
| r | 以只读的方式打开文本,也就意味着不能用write来操作文件 |
| rw | 读操作和写操作都是允许的 |
| rws | 每当进行写操作,同步的刷新到磁盘,刷新内容和元数据 |
| rwd | 每当进行写操作,同步的刷新到磁盘,刷新内容 |
下面让我们看看RandomAccessFile为我们提供的方法:
可以看出RandomAccessFile实现了大部分文件输入输出流的方法,但是底层实现中他实现的是DataInput和DataOutput接口,并非是FileInputStream和FileOutputStream。RandomAccessFile使用很多native方法实现了对文件的操作,并且很多native方法跟inputstream都有重叠,比如read0方法。我想这么做可能是为了让这个DataInput接口的职责更明确吧。
![]() | ![]() |
从上述对比中可以看出,datainput更注视强化对数据的各种既定操作。并没有出现类似inputstream的方法,也许这就是我们常说的单一职责原则吧。
二、实际操作一下吧
定义一个文件
编写一个方便我们使用的工厂类:
public class RAFTestFactory
private static final String url = "D:\\EclipseWorkspace\\text\\test.txt";
private static final String [] model = {"r","rw","rws","rwd"};
public static RandomAccessFile getRAFWithModelR() throws FileNotFoundException {
RandomAccessFile raf = new RandomAccessFile(new File(url), model[0]);
return raf;
}
public static RandomAccessFile getRAFWithModelRW() throws FileNotFoundException {
RandomAccessFile raf = new RandomAccessFile(new File(url), model[1]);
return raf;
}
public static RandomAccessFile getRAFWithModelRWS() throws FileNotFoundException {
RandomAccessFile raf = new RandomAccessFile(new File(url), model[2]);
return raf;
}
public static RandomAccessFile getRAFWithModelRWD() throws FileNotFoundException {
RandomAccessFile raf = new RandomAccessFile(new File(url), model[3]);
return raf;
}
} 编写测试类1:
-
public class RAFTestMain { public static void main(String[] args) throws IOException { RandomAccessFile raf = RAFTestFactory.getRAFWithModelR(); System.out.println("raf.length()->获取文本内容长度:"+raf.length()); System.out.println("raf.getFilePointer()->获取文本头指针:"+raf.getFilePointer()); raf.seek(4); System.out.println("raf.getFilePointer()->第二次获取文本头指针:"+raf.getFilePointer()); } }
看一下结果,体验一下seek的含义
raf.length()->获取文本内容长度:9
raf.getFilePointer()->获取文本头指针:0
raf.getFilePointer()->第二次获取文本头指针:4
编写测试类2:
-
public class RAFTestMain { public static void main(String[] args) throws IOException { RandomAccessFile raf = RAFTestFactory.getRAFWithModelR(); raf.write(1); } }
为什么出现这个结果,就是因为我们使用了 R model,也就是只读模式,这是写入会报错。
编写测试类3:
public class RAFTestMain {
public static void main(String[] args) throws IOException {
RandomAccessFile raf = RAFTestFactory.getRAFWithModelRW();
String word = "ljh";
raf.write(word.getBytes());
}
} 可以看到我们写的位置就是当前光标的位置,这个时候让我们结合seek和write试验一下吧。
编写测试类4:
public class RAFTestMain {
public static void main(String[] args) throws IOException {
RandomAccessFile raf = RAFTestFactory.getRAFWithModelRW();
raf.seek(4);
String word = "ljh";
raf.write(word.getBytes());
}
} 看,此时我们很方便的实现了插入操作。这是其他类无法实现的功能。也是这个类的强大之处。
编写测试类5:
最后我们看看
readDouble() readFloat() readBoolean() readInt() readLong() readShort() readByte() readChar()
writeDouble() writeFloat() writeBoolean() writeInt() writeLong() writeShort() writeByte() writeChar()
他们都怎么用的
public class RAFTestMain {
public static void main(String[] args) throws IOException {
RandomAccessFile raf = RAFTestFactory.getRAFWithModelRW();
raf.writeByte(3);
raf.writeChar('a');
raf.writeShort(5);
raf.writeInt(6);
raf.writeLong(792929347162343l);
raf.writeFloat(8.5f);
raf.writeDouble(9.44d);
raf.writeBoolean(true);
}
} 真是仙的不行,反正我是看不出个所以然。
三、对该工具类的价值分析
1、大型文本日志类文件的快速定位获取数据:
得益于seek的巧妙设计,我认为我们可以从超大的文本中快速定位我们的游标,例如每次存日志的时候,我们可以建立一个索引缓存,索引是日志的起始日期,value是文本的poiniter 也就是光标,这样我们可以快速定位某一个时间段的文本内容
2、并发读写
emmm也是得益于seek的设计,我认为多线程可以轮流操作seek控制光标的位置,从未达到不同线程的并发写操作。
3、更方便的获取二进制文件
通过自带的读写转码(readDouble、writeLong等),我认为可以快速的完成字节码到字符的转换功能,对使用者来说比较友好。
后续如果自己有想法,多做实验,多看源码。ok太晚了 睡觉了。。。


















还没有评论,来说两句吧...