最近,我碰到了这篇文章,这篇文章很好地介绍了内存映射文件以及如何在两个进程之间共享它。这是读取文件的过程的代码:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class MemoryMapReader {
/**
* @param args
* @throws IOException
* @throws FileNotFoundException
* @throws InterruptedException
*/
public static void main(String[] args) throws FileNotFoundException, IOException, InterruptedException {
FileChannel fc = new RandomAccessFile(new File("c:/tmp/mapped.txt"), "rw").getChannel();
long bufferSize=8*1000;
MappedByteBuffer mem = fc.map(FileChannel.MapMode.READ_ONLY, 0, bufferSize);
long oldSize=fc.size();
long currentPos = 0;
long xx=currentPos;
long startTime = System.currentTimeMillis();
long lastValue=-1;
for(;;)
{
while(mem.hasRemaining())
{
lastValue=mem.getLong();
currentPos +=8;
}
if(currentPos < oldSize)
{
xx = xx + mem.position();
mem = fc.map(FileChannel.MapMode.READ_ONLY,xx, bufferSize);
continue;
}
else
{
long end = System.currentTimeMillis();
long tot = end-startTime;
System.out.println(String.format("Last Value Read %s , Time(ms) %s ",lastValue, tot));
System.out.println("Waiting for message");
while(true)
{
long newSize=fc.size();
if(newSize>oldSize)
{
oldSize = newSize;
xx = xx + mem.position();
mem = fc.map(FileChannel.MapMode.READ_ONLY,xx , oldSize-xx);
System.out.println("Got some data");
break;
}
}
}
}
}
}
但是,我对这种方法有几点评论/问题:
如果我们仅对空文件执行读取器,即运行
long bufferSize=8*1000;
MappedByteBuffer mem = fc.map(FileChannel.MapMode.READ_ONLY, 0, bufferSize);
long oldSize=fc.size();
这将分配8000个字节,现在将扩展文件。返回的缓冲区的限制为8000,位置为0,因此,读取器可以继续读取空数据。发生这种情况后,阅读器将停止,如currentPos
== oldSize。
现在应该是作家了(代码被省去了,因为它很简单,可以从网站上引用)-它使用相同的缓冲区大小,因此它将先写入8000个字节,然后再分配8000个字节,以扩展文件。现在,如果我们假设此过程在此时暂停,然后返回到读取器,那么读取器将看到文件的新大小并分配剩余的文件(因此从位置8000到1600),然后再次开始读取,然后再读取垃圾…
我有点困惑是否有一个为什么要同步这两个操作。据我所知,任何对的调用都map可能会使用一个真正的空缓冲区(用零填充)扩展文件,或者编写器可能刚刚扩展了文件,但尚未向其中写入任何内容…