[Java] NIO写大文件比较 →→→→→进入此内容的聊天室

来自 , 2020-04-06, 写在 Java, 查看 177 次.
URL http://www.code666.cn/view/e58cc5ca
  1. package rwbigfile;
  2.  
  3. import java.io.ByteArrayInputStream;
  4. import java.io.File;
  5. import java.io.IOException;
  6. import java.io.RandomAccessFile;
  7. import java.lang.reflect.Method;
  8. import java.nio.ByteBuffer;
  9. import java.nio.MappedByteBuffer;
  10. import java.nio.channels.Channels;
  11. import java.nio.channels.FileChannel;
  12. import java.nio.channels.FileChannel.MapMode;
  13. import java.nio.channels.ReadableByteChannel;
  14. import java.security.AccessController;
  15. import java.security.PrivilegedAction;
  16.  
  17. import util.StopWatch;
  18.  
  19. /**
  20.  * NIO写大文件比较
  21.  * @author Will
  22.  *
  23.  */
  24. public class WriteBigFileComparison {
  25.  
  26.         // data chunk be written per time
  27.         private static final int DATA_CHUNK = 128 * 1024 * 1024;
  28.  
  29.         // total data size is 2G
  30.         private static final long LEN = 2L * 1024 * 1024 * 1024L;
  31.  
  32.        
  33.         public static void writeWithFileChannel() throws IOException {
  34.                 File file = new File("e:/test/fc.dat");
  35.                 if (file.exists()) {
  36.                         file.delete();
  37.                 }
  38.  
  39.                 RandomAccessFile raf = new RandomAccessFile(file, "rw");
  40.                 FileChannel fileChannel = raf.getChannel();
  41.  
  42.                 byte[] data = null;
  43.                 long len = LEN;
  44.                 ByteBuffer buf = ByteBuffer.allocate(DATA_CHUNK);
  45.                 int dataChunk = DATA_CHUNK / (1024 * 1024);
  46.                 while (len >= DATA_CHUNK) {
  47.                         System.out.println("write a data chunk: " + dataChunk + "MB");
  48.  
  49.                         buf.clear(); // clear for re-write
  50.                         data = new byte[DATA_CHUNK];
  51.                         for (int i = 0; i < DATA_CHUNK; i++) {
  52.                                 buf.put(data[i]);
  53.                         }
  54.  
  55.                         data = null;
  56.  
  57.                         buf.flip(); // switches a Buffer from writing mode to reading mode
  58.                         fileChannel.write(buf);
  59.                         fileChannel.force(true);
  60.  
  61.                         len -= DATA_CHUNK;
  62.                 }
  63.  
  64.                 if (len > 0) {
  65.                         System.out.println("write rest data chunk: " + len + "B");
  66.                         buf = ByteBuffer.allocateDirect((int) len);
  67.                         data = new byte[(int) len];
  68.                         for (int i = 0; i < len; i++) {
  69.                                 buf.put(data[i]);
  70.                         }
  71.  
  72.                         buf.flip(); // switches a Buffer from writing mode to reading mode, position to 0, limit not changed
  73.                         fileChannel.write(buf);
  74.                         fileChannel.force(true);
  75.                         data = null;
  76.                 }
  77.  
  78.                 fileChannel.close();
  79.                 raf.close();
  80.         }
  81.  
  82.         /**
  83.          * write big file with MappedByteBuffer
  84.          * @throws IOException
  85.          */
  86.         public static void writeWithMappedByteBuffer() throws IOException {
  87.                 File file = new File("e:/test/mb.dat");
  88.                 if (file.exists()) {
  89.                         file.delete();
  90.                 }
  91.  
  92.                 RandomAccessFile raf = new RandomAccessFile(file, "rw");
  93.                 FileChannel fileChannel = raf.getChannel();
  94.                 int pos = 0;
  95.                 MappedByteBuffer mbb = null;
  96.                 byte[] data = null;
  97.                 long len = LEN;
  98.                 int dataChunk = DATA_CHUNK / (1024 * 1024);
  99.                 while (len >= DATA_CHUNK) {
  100.                         System.out.println("write a data chunk: " + dataChunk + "MB");
  101.  
  102.                         mbb = fileChannel.map(MapMode.READ_WRITE, pos, DATA_CHUNK);
  103.                         data = new byte[DATA_CHUNK];
  104.                         mbb.put(data);
  105.  
  106.                         data = null;
  107.  
  108.                         len -= DATA_CHUNK;
  109.                         pos += DATA_CHUNK;
  110.                 }
  111.  
  112.                 if (len > 0) {
  113.                         System.out.println("write rest data chunk: " + len + "B");
  114.  
  115.                         mbb = fileChannel.map(MapMode.READ_ONLY, pos, len);
  116.                         data = new byte[(int) len];
  117.                         mbb.put(data);
  118.                 }
  119.  
  120.                 data = null;
  121.                 unmap(mbb);   // release MappedByteBuffer
  122.                 fileChannel.close();
  123.         }
  124.        
  125.         public static void writeWithTransferTo() throws IOException {
  126.                 File file = new File("e:/test/transfer.dat");
  127.                 if (file.exists()) {
  128.                         file.delete();
  129.                 }
  130.                
  131.                 RandomAccessFile raf = new RandomAccessFile(file, "rw");
  132.                 FileChannel toFileChannel = raf.getChannel();
  133.                
  134.                 long len = LEN;
  135.                 byte[] data = null;
  136.                 ByteArrayInputStream bais = null;
  137.                 ReadableByteChannel fromByteChannel = null;
  138.                 long position = 0;
  139.                 int dataChunk = DATA_CHUNK / (1024 * 1024);
  140.                 while (len >= DATA_CHUNK) {
  141.                         System.out.println("write a data chunk: " + dataChunk + "MB");
  142.                        
  143.                         data = new byte[DATA_CHUNK];
  144.                         bais = new ByteArrayInputStream(data);
  145.                         fromByteChannel = Channels.newChannel(bais);
  146.                        
  147.                         long count = DATA_CHUNK;
  148.                         toFileChannel.transferFrom(fromByteChannel, position, count);
  149.                        
  150.                         data = null;
  151.                         position += DATA_CHUNK;
  152.                         len -= DATA_CHUNK;
  153.                 }
  154.                
  155.                 if (len > 0) {
  156.                         System.out.println("write rest data chunk: " + len + "B");
  157.  
  158.                         data = new byte[(int) len];
  159.                         bais = new ByteArrayInputStream(data);
  160.                         fromByteChannel = Channels.newChannel(bais);
  161.                        
  162.                         long count = len;
  163.                         toFileChannel.transferFrom(fromByteChannel, position, count);
  164.                 }
  165.                
  166.                 data = null;
  167.                 toFileChannel.close();
  168.                 fromByteChannel.close();
  169.         }
  170.        
  171.         /**
  172.          * 在MappedByteBuffer释放后再对它进行读操作的话就会引发jvm crash,在并发情况下很容易发生
  173.          * 正在释放时另一个线程正开始读取,于是crash就发生了。所以为了系统稳定性释放前一般需要检
  174.          * 查是否还有线程在读或写
  175.          * @param mappedByteBuffer
  176.          */
  177.         public static void unmap(final MappedByteBuffer mappedByteBuffer) {
  178.                 try {
  179.                         if (mappedByteBuffer == null) {
  180.                                 return;
  181.                         }
  182.                        
  183.                         mappedByteBuffer.force();
  184.                         AccessController.doPrivileged(new PrivilegedAction<Object>() {
  185.                                 @Override
  186.                                 @SuppressWarnings("restriction")
  187.                                 public Object run() {
  188.                                         try {
  189.                                                 Method getCleanerMethod = mappedByteBuffer.getClass()
  190.                                                                 .getMethod("cleaner", new Class[0]);
  191.                                                 getCleanerMethod.setAccessible(true);
  192.                                                 sun.misc.Cleaner cleaner =
  193.                                                                 (sun.misc.Cleaner) getCleanerMethod
  194.                                                                         .invoke(mappedByteBuffer, new Object[0]);
  195.                                                 cleaner.clean();
  196.                                                
  197.                                         } catch (Exception e) {
  198.                                                 e.printStackTrace();
  199.                                         }
  200.                                         System.out.println("clean MappedByteBuffer completed");
  201.                                         return null;
  202.                                 }
  203.                         });
  204.  
  205.                 } catch (Exception e) {
  206.                         e.printStackTrace();
  207.                 }
  208.         }
  209.  
  210.         public static void main(String[] args) throws IOException {
  211.                 StopWatch sw = new StopWatch();
  212.                
  213.                 sw.startWithTaskName("write with file channel's write(ByteBuffer)");
  214.                 writeWithFileChannel();
  215.                 sw.stopAndPrint();
  216.                
  217.                 sw.startWithTaskName("write with file channel's transferTo");
  218.                 writeWithTransferTo();
  219.                 sw.stopAndPrint();
  220.                
  221.                 sw.startWithTaskName("write with MappedByteBuffer");
  222.                 writeWithMappedByteBuffer();
  223.                 sw.stopAndPrint();
  224.         }
  225.  
  226. }//源代码片段来自云代码http://yuncode.net
  227.                        

回复 "NIO写大文件比较"

这儿你可以回复上面这条便签

captcha