java nio 大文件_Java NIO写大文件比较

本文通过WriteBigFileComparison类展示了使用Java NIO的FileChannel、MappedByteBuffer和TransferTo方法分别写入2GB大文件的性能比较,探讨了不同方式的优缺点,旨在提供文件I/O操作的最佳实践。
摘要由CSDN通过智能技术生成

package rwbigfile;

import java.io.ByteArrayInputStream;

import java.io.File;

import java.io.IOException;

import java.io.RandomAccessFile;

import java.lang.reflect.Method;

import java.nio.ByteBuffer;

import java.nio.MappedByteBuffer;

import java.nio.channels.Channels;

import java.nio.channels.FileChannel;

import java.nio.channels.FileChannel.MapMode;

import java.nio.channels.ReadableByteChannel;

import java.security.AccessController;

import java.security.PrivilegedAction;

import util.StopWatch;

/**

* NIO写大文件比较

* @author Will

*

*/

public class WriteBigFileComparison {

// data chunk be written per time

private static final int DATA_CHUNK = 128 * 1024 * 1024;

// total data size is 2G

private static final long LEN = 2L * 1024 * 1024 * 1024L;

public static void writeWithFileChannel() throws IOException {

File file = new File("e:/test/fc.dat");

if (file.exists()) {

file.delete();

}

RandomAccessFile raf = new RandomAccessFile(file, "rw");

FileChannel fileChannel = raf.getChannel();

byte[] data = null;

long len = LEN;

ByteBuffer buf = ByteBuffer.allocate(DATA_CHUNK);

int dataChunk = DATA_CHUNK / (1024 * 1024);

while (len >= DATA_CHUNK) {

System.out.println("write a data chunk: " + dataChunk + "MB");

buf.clear(); // clear for re-write

data = new byte[DATA_CHUNK];

for (int i = 0; i 

buf.put(data[i]);

}

data = null;

buf.flip(); // switches a Buffer from writing mode to reading mode

fileChannel.write(buf);

fileChannel.force(true);

len -= DATA_CHUNK;

}

if (len > 0) {

System.out.println("write rest data chunk: " + len + "B");

buf = ByteBuffer.allocateDirect((int) len);

data = new byte[(int) len];

for (int i = 0; i 

buf.put(data[i]);

}

buf.flip(); // switches a Buffer from writing mode to reading mode, position to 0, limit not changed

fileChannel.write(buf);

fileChannel.force(true);

data = null;

}

fileChannel.close();

raf.close();

}

/**

* write big file with MappedByteBuffer

* @throws IOException

*/

public static void writeWithMappedByteBuffer() throws IOException {

File file = new File("e:/test/mb.dat");

if (file.exists()) {

file.delete();

}

RandomAccessFile raf = new RandomAccessFile(file, "rw");

FileChannel fileChannel = raf.getChannel();

int pos = 0;

MappedByteBuffer mbb = null;

byte[] data = null;

long len = LEN;

int dataChunk = DATA_CHUNK / (1024 * 1024);

while (len >= DATA_CHUNK) {

System.out.println("write a data chunk: " + dataChunk + "MB");

mbb = fileChannel.map(MapMode.READ_WRITE, pos, DATA_CHUNK);

data = new byte[DATA_CHUNK];

mbb.put(data);

data = null;

len -= DATA_CHUNK;

pos += DATA_CHUNK;

}

if (len > 0) {

System.out.println("write rest data chunk: " + len + "B");

mbb = fileChannel.map(MapMode.READ_WRITE, pos, len);

data = new byte[(int) len];

mbb.put(data);

}

data = null;

unmap(mbb);   // release MappedByteBuffer

fileChannel.close();

}

public static void writeWithTransferTo() throws IOException {

File file = new File("e:/test/transfer.dat");

if (file.exists()) {

file.delete();

}

RandomAccessFile raf = new RandomAccessFile(file, "rw");

FileChannel toFileChannel = raf.getChannel();

long len = LEN;

byte[] data = null;

ByteArrayInputStream bais = null;

ReadableByteChannel fromByteChannel = null;

long position = 0;

int dataChunk = DATA_CHUNK / (1024 * 1024);

while (len >= DATA_CHUNK) {

System.out.println("write a data chunk: " + dataChunk + "MB");

data = new byte[DATA_CHUNK];

bais = new ByteArrayInputStream(data);

fromByteChannel = Channels.newChannel(bais);

long count = DATA_CHUNK;

toFileChannel.transferFrom(fromByteChannel, position, count);

data = null;

position += DATA_CHUNK;

len -= DATA_CHUNK;

}

if (len > 0) {

System.out.println("write rest data chunk: " + len + "B");

data = new byte[(int) len];

bais = new ByteArrayInputStream(data);

fromByteChannel = Channels.newChannel(bais);

long count = len;

toFileChannel.transferFrom(fromByteChannel, position, count);

}

data = null;

toFileChannel.close();

fromByteChannel.close();

}

/**

* 在MappedByteBuffer释放后再对它进行读操作的话就会引发jvm crash,在并发情况下很容易发生

* 正在释放时另一个线程正开始读取,于是crash就发生了。所以为了系统稳定性释放前一般需要检

* 查是否还有线程在读或写

* @param mappedByteBuffer

*/

public static void unmap(final MappedByteBuffer mappedByteBuffer) {

try {

if (mappedByteBuffer == null) {

return;

}

mappedByteBuffer.force();

AccessController.doPrivileged(new PrivilegedAction() {

@Override

@SuppressWarnings("restriction")

public Object run() {

try {

Method getCleanerMethod = mappedByteBuffer.getClass()

.getMethod("cleaner", new Class[0]);

getCleanerMethod.setAccessible(true);

sun.misc.Cleaner cleaner =

(sun.misc.Cleaner) getCleanerMethod

.invoke(mappedByteBuffer, new Object[0]);

cleaner.clean();

} catch (Exception e) {

e.printStackTrace();

}

System.out.println("clean MappedByteBuffer completed");

return null;

}

});

} catch (Exception e) {

e.printStackTrace();

}

}

public static void main(String[] args) throws IOException {

StopWatch sw = new StopWatch();

sw.startWithTaskName("write with file channel's write(ByteBuffer)");

writeWithFileChannel();

sw.stopAndPrint();

sw.startWithTaskName("write with file channel's transferTo");

writeWithTransferTo();

sw.stopAndPrint();

sw.startWithTaskName("write with MappedByteBuffer");

writeWithMappedByteBuffer();

sw.stopAndPrint();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值