我目前正在使用RandomAccessFile并遇到一个奇怪的现象。 我正在访问一个1.1TB大的文件,只包含质量为00000000的字节。
我以下列方式实现了RandomAccessFile:
RandomAccessFile raf = new RandomAccessFile(new File("./db.bin"),"rw");
所以我的程序生成一个表示BIT位置的Long值的大列表,一旦达到1000 Entrys,它就会将数据刷新到文件中:
public void flush() {
for( long l : lLongs ) {
lseek = Long.divideUnsigned(l, 8L);
raf.seek( lseek );
byte b = raf.readByte();
raf.seek( lseek );
raf.writeByte( editByte(b,(int)l % 8) );
}
raf.close();
}
public byte editByte( byte b, int iBit ) {
if( !isSet(b,iBit) ) {
b = (byte)(b + Math.pow( 2, iBit));
}
return b;
}
boolean isSet(byte value, int bit){
return (value >> bit & 1) == 1;
}
现在我想知道为什么需要这么长时间? 1000个Entrys平均需要15个。 但是,如果我取消我的程序并重新启动它,我将只需要5ms进行1000次托管(长仓保持不变)
为什么?有人可以帮我解决这个问题吗?
答案 0 :(得分:1)
逻辑上的解释是,第一次启动需要实际读取文件,另一次启动从内存缓存中获取文件,速度要快得多。
同样第二次,如果我读得正确,你不需要写数据。
如果你想要更好的东西,你可以尝试使用顺序的东西:
private static final int CHUNK_SIZE=512*8*1024; // 4Mb chunk
private RandomAccessFile raf;
private long currentChunk=-1;
private byte[] chunk=new byte[CHUNK_SIZE];
public void flush() throws Exception{
raf = new RandomAccessFile(new File("./db.bin"),"rw");
List<Long> c=something();
c.stream().sorted().forEach(this::process);
saveChunk();
}
public void process(long l) {
try {
if (l/8/CHUNCK_SIZE!=currentChunk) {
saveChunk();
loadNextChunk();
}
long posInMem=(l/8) - (CHUNK_SIZE*currentChunk);
byte b=chunk[(int)posInMem];
chunk[(int)posInMem]=editByte(b,(int)l % 8);
}catch(Exception e) {
e.printStackTrace();
}
}
private void loadNextChunk()throws Exception {
currentChunk++;
raf.seek(currentChunk*CHUNK_SIZE);
raf.readFully(chunk, 0, CHUNK_SIZE);
}
private void saveChunk() throws Exception {
if (currentChunk<0)return;
raf.seek(currentChunk*CHUNK_SIZE);
raf.write(chunk, 0, CHUNK_SIZE);
}