我最近遇到了这个
article,它为内存映射文件提供了一个很好的介绍,以及它如何在两个进程之间共享.以下是读入文件的进程的代码:
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,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,oldSize-xx); System.out.println("Got some data"); break; } } } } } }
但是,我对这种方法提出了一些意见/问题:
如果我们只在空文件上执行阅读器,即运行
long bufferSize=8*1000; MappedByteBuffer mem = fc.map(FileChannel.MapMode.READ_ONLY,bufferSize); long oldSize=fc.size();
这将分配8000个字节,现在将扩展该文件.返回的缓冲区的限制为8000,位置为0,因此,读者可以继续读取空数据.发生这种情况后,读者将停止,因为currentPos == oldSize.
据说现在编写进来(代码被省略,因为大部分内容都很简单,可以从网站上引用) – 它使用相同的缓冲区大小,因此它将首先写入8000个字节,然后分配另外8000个,扩展文件.现在,如果我们假设这个过程暂停,然后我们回到阅读器,那么读者会看到文件的新大小并分配剩余部分(从位置8000到1600)并再次开始阅读,阅读另一个垃圾…
我是否有同步这两个操作的原因有点困惑.据我所知,任何对map的调用都可能会扩展文件,实际上是一个空缓冲区(用零填充)或者编写器可能刚刚扩展了文件,但还没有写入任何东西……
解决方法
有几种方法.
>让作者获得尚未编写的区域的独家锁定.在写完所有内容后释放锁定.这与在该系统上运行的每个其他应用程序兼容,但它要求读者足够聪明以重试失败的读取,除非您将其与其他方法之一结合使用
>使用另一个通信渠道,例如管道或套接字或文件的元数据通道,让作者告诉读者完成的写入.
>在文件中的一个位置写一个特殊的标记(作为协议的一部分),告诉写入的数据,例如
MappedByteBuffer bb; … // write your data bb.force();// ensure completion of all writes bb.put(specialPosition,specialMarkerValue); bb.force();// ensure visibility of the marker