首页 > 代码库 > 转:Java NIO(3)

转:Java NIO(3)

要想讲清楚nio的原理和它的优点得先清楚Java应用程序的文件读写原理和虚拟内存的原理。Java文件读取原理可参见如下图:

技术分享

当应用程序需要读取文件的时候,内核首先通过DMA技术将文件内容从磁盘读入内核中的buffer,然后Java应用进程再从内核的buffer将数据读取到应用程序的buffer。

为了提升I/O效率和处理能力,操作系统采用虚拟内存的机制。虚拟内存也就是我们常说的交换内存,它实际上是硬盘上的文件,虚拟内存有两个作用:

1. 不同的虚拟内存可以映射到相同的物理内存,根据这个原理,可以简化文件读取流程,提升读取效率,效果如下图所示:

技术分享

通过使用虚拟内存技术,将应用程序的buffer和内核的buffer都作为虚拟内存,并且两块不同的虚拟内存指向相同的物理内存,内核通过DMA将数据读取到buffer的时候,应用程序就可以直接使用这些数据了。

2. 通过使用虚拟内存, 应用程序可以使用比物理内存所能容纳得大得多的内存,并且也能够提高I/O效率。当物理内存中的数据不使用的时候,可以将物理内存中的数据放到虚拟内存中,操作系统就可以腾出物理内存空间存储新的要处理的数据。当需要使用虚拟内存中的数据时,再可以把虚拟内存中的数据加载到物理内存中。因此物理内存可以看做时虚拟内存中存放数据的cache。而上面所述的cache虚拟内存数据的过程,对应用程序来说时透明的,它可以像处理物理内存数据一样处理虚拟内存中的数据。


Java nio通过使用虚拟内存技术将文件系统中的文件页和应用程序空间直接对应起来,使用nio后,文件的读写操作都是在虚拟内存中实现。这样在操作文件的时候,好像文件已经在内存中一样。采用了虚拟内存技术,使用Java nio方式可以很快的读取很大的文件。

Java nio打开文件可指定映射内容在所要映射的文件所在位置。使用Java nio打开文件源码:

[java] view plain copy
  1. import java.io.RandomAccessFile;  
  2. import java.nio.MappedByteBuffer;  
  3. import java.nio.channels.FileChannel;  
  4.    
  5. public class MemoryMappedFileExample  
  6. {  
  7.     static int length = 0x8FFFFFF; // 128 Mb  
  8.    
  9.     public static void main(String[] args) throws Exception  
  10.     {  
  11.         MappedByteBuffer out = new RandomAccessFile("howtodoinjava.dat", "rw")  
  12.                                     .getChannel().map(FileChannel.MapMode.READ_WRITE, 0, length);  
  13.         for (int i = 0; i < length; i++)  
  14.         {  
  15.             out.put((byte) ‘x‘);  
  16.         }  
  17.         System.out.println("Finished writing");  
  18.     }  
  19. }  



使用Java nio读取文件内容源码:

[java] view plain copy
  1. import java.io.File;  
  2. import java.io.RandomAccessFile;  
  3. import java.nio.MappedByteBuffer;  
  4. import java.nio.channels.FileChannel;  
  5.    
  6. public class MemoryMappedFileReadExample  
  7. {  
  8.     private static String bigExcelFile = "bigFile.xls";  
  9.    
  10.     public static void main(String[] args) throws Exception  
  11.     {  
  12.         //Create file object  
  13.         File file = new File(bigExcelFile);  
  14.            
  15.         //Get file channel in readonly mode  
  16.         FileChannel fileChannel = new RandomAccessFile(file, "r").getChannel();  
  17.            
  18.         //Get direct byte buffer access using channel.map() operation  
  19.         MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());  
  20.            
  21.         // the buffer now reads the file as if it were loaded in memory.  
  22.         System.out.println(buffer.isLoaded());  //prints false  
  23.         System.out.println(buffer.capacity());  //Get the size based on content size of file  
  24.            
  25.         //You can read the file from this buffer the way you like.  
  26.         for (int i = 0; i < buffer.limit(); i++)  
  27.         {  
  28.             System.out.print((char) buffer.get()); //Print the content of file  
  29.         }  
  30.     }  
  31. }  


使用Java nio写入文件新的内容:

[java] view plain copy
  1. import java.io.File;  
  2. import java.io.RandomAccessFile;  
  3. import java.nio.MappedByteBuffer;  
  4. import java.nio.channels.FileChannel;  
  5.    
  6. public class MemoryMappedFileWriteExample {  
  7.     private static String bigExcelFile = "test.txt";  
  8.    
  9.     public static void main(String[] args) throws Exception {  
  10.         // Create file object  
  11.         File file = new File(bigExcelFile);  
  12.            
  13.         //Delete the file; we will create a new file  
  14.         file.delete();  
  15.    
  16.         // Get file channel in readonly mode  
  17.         FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel();  
  18.    
  19.         // Get direct byte buffer access using channel.map() operation  
  20.         MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, 4096 * 8 * 8);  
  21.    
  22.         //Write the content using put methods  
  23.         buffer.put("howtodoinjava.com".getBytes());  
  24.     }  
  25. }  


可见Java nio的优势为:

1. 不需要使用read()或者write()操作就可以处理文件内容了

2. 修改文件后,修改自动flush到文件

3. nio方式能很快处理大文件和处理效率很快


参考文章:

http://howtodoinjava.com/2014/12/10/how-java-io-works-internally-at-lower-level/

http://howtodoinjava.com/2015/01/16/java-nio-2-0-memory-mapped-files-mappedbytebuffer-tutorial/


转:Java NIO(3)