學習JavaNIO-檔案記憶體映射

來源:互聯網
上載者:User
學習JavaNIO-檔案記憶體映射
    部落格分類:
  • Java-NIO
最近看了檔案記憶體映射。在NIO中,使用起來很方便。
檔案通過記憶體映射以後,訪問速度自然是提高了。
當然也有很多問題,現在我們來看看NIO中的記憶體對應檔。

Java代碼
  1. public abstract class FileChannel extends  
  2. AbstractChannel implements ByteChannel, GatheringByteChannel, ScatteringByteChannel { 
  3. // This is a partial API listing 
  4. public abstract MappedByteBuffer map (MapMode mode, long position,long size)  
  5. public static class MapMode {  
  6.     public static final MapMode READ_ONLY  
  7.     public static final MapMode READ_WRITE  
  8.     public static final MapMode PRIVATE  
  9.     }  
public abstract class FileChannel extends AbstractChannel implements ByteChannel, GatheringByteChannel, ScatteringByteChannel { // This is a partial API listingpublic abstract MappedByteBuffer map (MapMode mode, long position,long size) public static class MapMode { public static final MapMode READ_ONLY public static final MapMode READ_WRITE public static final MapMode PRIVATE } }

記憶體對應檔,是通過一個FileChannel來完成的,返回的MappedByteBuffer,也是一種ByteBuffer。這裡有三種映射模式。主要針對這三種映射模式的差異說說。

根據map函數,我們得知,我們可以映射部分檔案,也可以全部映射。
如果請求的大小,size超出檔案,那麼檔案會相應的增長以對應映射。如果是Integer.MAX_VALUE,那麼檔案就會達到2.1GB
當然,如果你請求的只是一個唯讀檔案,而你的size超出檔案大小,那麼就會拋出IOException。
對於 MapMode的前兩種,READ_ONLY和READ_WRITE來說,都很好理解。要注意的而是,如果在一個唯讀檔案上使用READ_WRITE,是要拋出NonWritableChannelException異常的。
MapMode.PRIVATE模式很有意思,稱為“寫時拷貝”(copy-on-write)的映射。這是作業系統中常用的技術。比如建立一個子進程時,子進程共用父進程的地址空間,當子進程修改空間的時候,才會拷貝要修改的部分。對於PRIVATE模式來說,只有使用put函數的時候,才會去拷貝。可能拷貝某一頁或者幾頁。假設此時有其他的映射,是看不到本次put後的改變的。也就是說,私人的。

注意,沒有unmap函數,也就是說,一旦map成功,那麼即使FileChannel被關閉,映射依然存在,只有映射對應的MappedByteBuffer記憶體被回收,映射才算取消。

MappedByteBuffer直接反應磁碟檔案,如果磁碟檔案結構或大小改變,那麼可能就無法訪問檔案。
MappedByteBuffer 直接記憶體存取,並不佔用虛擬機器記憶體。
MappedByteBuffer 也是ByteBuffer,所以可以用於SocketChannel之類的通道讀寫。
對於MappedByteBuffer還有幾個函數可以介紹下。Java代碼

  1. public abstract class MappedByteBuffer extends ByteBuffer {  
  2. // This is a partial API listing  
  3. public final MappedByteBuffer load( )  
  4. public final boolean isLoaded( )  
  5. public final MappedByteBuffer force( )  
public abstract class MappedByteBuffer extends ByteBuffer { // This is a partial API listing public final MappedByteBuffer load( ) public final boolean isLoaded( ) public final MappedByteBuffer force( ) }

load函數用於從磁碟檔案載入到記憶體。這個操作將會引起大量系統調用。慎用。一旦載入完成,再次訪問檔案,就和訪問記憶體一樣快。但是,這些都起決於作業系統底層調用。

isLoaded函數是用來判斷檔案是否完全載入到記憶體。

force則是強制同步記憶體檔案到磁碟。也就是把MappedByteBuffer中的更改應用到磁碟中。這裡包括了檔案的中繼資料(最近一次訪問,作者,建立時間等)。當然,如果是READ_ONLY或者PRIVATE模式,則不起作用。

下面這個例子,使用記憶體對應檔,產生一個HTTP應答格式的檔案。我們來看看這個例子:Java代碼

  1. package shaoxin.nio; 
  2.  
  3. import java.io.FileInputStream; 
  4. import java.io.FileOutputStream; 
  5. import java.io.IOException; 
  6. import java.net.URLConnection; 
  7. import java.nio.ByteBuffer; 
  8. import java.nio.MappedByteBuffer; 
  9. import java.nio.channels.FileChannel; 
  10. import java.nio.channels.FileChannel.MapMode; 
  11.  
  12. /***
  13. * Dummy HTTP server using MappedByteBuffer.
  14. * Given a filename on the command line, pretend to be
  15. * a web server and generate an HTTP response containing
  16. * the file content preceded by appropriate headers The
  17. * data is send with a gathering write.
  18. *
  19. * @author Ron Hitchens (ron@ronsoft.com)
  20. *
  21. */ 
  22. public class MappedHttp { 
  23.     private static final String OUTPUT_FILE="MappedHttp.out"; 
  24.     private static final String LINE_SEP = "\r\n"; 
  25.     private static final String SERVER_ID = "Server: Ronsoft Dummy Server"; 
  26.     private static final String HTTP_HDR =  
  27.         "HTTP/1.0 200 OK" + LINE_SEP + SERVER_ID + LINE_SEP; 
  28.     private static final String HTTP_404_HDR =  
  29.         "HTTP/1.0 404 Not Found" + LINE_SEP + SERVER_ID + LINE_SEP; 
  30.     private static final String MSG_404 = "Cound not open file: "; 
  31.     public static void main(String[] args) throws Exception{ 
  32.         if(args.length < 1){ 
  33.             System.err.println("Usage:filename"); 
  34.             return; 
  35.         } 
  36.          
  37.         String file = args[0]; 
  38.         ByteBuffer header = ByteBuffer.wrap(bytes(HTTP_HDR)); 
  39.         ByteBuffer dynhdrs = ByteBuffer.allocate(128); 
  40.         ByteBuffer[] gather = {header,dynhdrs,null}; 
  41.         String contentType = "unknown/unknown"; 
  42.         long contentLength = -1; 
  43.         try{ 
  44.             FileInputStream fis = new FileInputStream(file); 
  45.             FileChannel fc = fis.getChannel(); 
  46.             MappedByteBuffer filedata =  
  47.                 fc.map(MapMode.READ_ONLY, 0, fc.size()); 
  48.             gather[2] = filedata; 
  49.             contentLength = fc.size(); 
  50.             contentType = URLConnection.guessContentTypeFromName(file); 
  51.         }catch(IOException e){ 
  52.             //file could not be opend; report problem 
  53.             ByteBuffer buf = ByteBuffer.allocate(128); 
  54.             String msg = MSG_404 + LINE_SEP; 
  55.             buf.put(bytes(msg)); 
  56.             buf.flip(); 
  57.             //Use the HTTP error response 
  58.             gather[0] = ByteBuffer.wrap(bytes(HTTP_404_HDR)); 
  59.             gather[2] = buf; 
  60.             contentLength = msg.length(); 
  61.             contentType = "text/plain"; 
  62.         } 
  63.          
  64.         StringBuffer sb = new StringBuffer(); 
  65.         sb.append("Content-Length: " + contentLength); 
  66.         sb.append(LINE_SEP); 
  67.         sb.append("Content-Type: ").append(contentType); 
  68.         sb.append(LINE_SEP).append(LINE_SEP); 
  69.         dynhdrs.put(bytes(sb.toString())); 
  70.         dynhdrs.flip(); 
  71.          
  72.         FileOutputStream fos = new FileOutputStream(OUTPUT_FILE); 
  73.         FileChannel out = fos.getChannel(); 
  74.         // All the buffers have been prepared , write them out 
  75.         while(out.write(gather) > 0){ 
  76.             //Empty body; loop until all buffers are empty           
  77.         } 
  78.         out.close(); 
  79.         System.out.println("output written to "+ OUTPUT_FILE); 
  80.     } 
  81.      
  82.     //Convert a String to its constituent bytes 
  83.     //from the ASCII character set 
  84.     private static byte[] bytes(String string)throws Exception { 
  85.         return (string.getBytes("US-ASCII")); 
  86.     } 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.