加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

Java NIO – 内存映射文件

发布时间:2020-12-15 02:57:04 所属栏目:Java 来源:网络整理
导读:我最近遇到了这个 article,它为内存映射文件提供了一个很好的介绍,以及它如何在两个进程之间共享.以下是读入文件的进程的代码: import java.io.File;import java.io.FileNotFoundException;import java.io.IOException;import java.io.RandomAccessFile;imp
我最近遇到了这个 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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读