我读了一篇关于转让副本的文章 位于 https://www.ibm.com/developerworks/library/j-zerocopy/。建议用户通道进行IO操作。
有一个复制文件操作的基准,位于 https://baptiste-wicht.com/posts/2010/08/file-copy-in-java-benchmark.html
根据基准测试,我可以使用 nio buffer 或 nio trasfer
我还阅读了FileChannel 在操作系统级别进行缓冲 这里如何在Java中实现缓冲/批处理的FileChannel?
使用缓冲区或不使用缓冲区复制文件哪种更有效。
nio 缓冲区代码
public static void nioBufferCopy(File sourceFile, File targetFile, int BUFFER) {
FileChannel inputChannel = null;
FileChannel outputChannel = null;
try {
inputChannel = new FileInputStream(sourceFile).getChannel();
outputChannel = new FileOutputStream(targetFile).getChannel();
ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER);
while (inputChannel.read(buffer) != -1) {
buffer.flip();
while(buffer.hasRemaining()){
outputChannel.write(buffer);
}
buffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//close resource
}
}
nio 转账代码
public void copyFileWithChannels(File aSourceFile, File aTargetFile) {
FileChannel inChannel = null;
FileChannel outChannel = null;
FileInputStream inStream = null;
FileOutputStream outStream = null;
try {
inStream = new FileInputStream(aSourceFile);
inChannel = inStream.getChannel();
outStream = new FileOutputStream(aTargetFile);
outChannel = outStream.getChannel();
long bytesTransferred = 0;
while(bytesTransferred < inChannel.size()){
bytesTransferred += inChannel.transferTo(bytesTransferred, inChannel.size(), outChannel);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
//close resource
}
}
这个问题之前被问过:
TL.DR.:您的 JVM 在什么上运行很重要,但大多数情况下
java.nio
稍微快一些。
我们有一个用例,需要复制 GB 的文件,我们的经验 NIO 优于传统 IO,但使用具有适当缓冲区大小的通道概念。通道提供跨多个缓冲区执行单个 I/O 操作的能力。我们使用了 FileChannel 的想法,与缓冲区相比,它是线程安全的,并且还支持当前文件位置的概念,有助于确定下一个数据项将被读取或写入的位置。 我们使用 ReadableByteChannel 和 WritableByteChannel 的实现是
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import org.apache.commons.io.IOUtils;
/**
* A file channel that leverages NIO classes internally to perform read/write operations on the provided streams to achieve high-performance I/O.
*
*/
public final class FileChannel implements Closeable {
// default buffer size used for reading and writing
private static final int BUFFER_SIZE = 65536;
private final ReadableByteChannel source;
private final WritableByteChannel destination;
private final int bufferSize;
private final boolean shouldClose;
public FileChannel(final InputStream source, final OutputStream destination) {
this(source, destination, BUFFER_SIZE, true);
}
public FileChannel(final InputStream source,
final OutputStream destination,
final boolean shouldClose) {
this(source, destination, BUFFER_SIZE, shouldClose);
}
public FileChannel(final InputStream source,
final OutputStream destination,
final int bufferSize,
final boolean shouldClose) {
this.source = Channels.newChannel(source);
this.destination = Channels.newChannel(destination);
this.bufferSize = bufferSize;
this.shouldClose = shouldClose;
}
/**
* Transfer bytes from source to destination stream.
*/
public void transfer() {
// Used Direct byte buffers because this is the most efficient means of performing I/O on the JVM
final ByteBuffer buffer = ByteBuffer.allocateDirect(this.bufferSize);
while (read(buffer) != -1) {
// prepare the buffer to be drained
buffer.flip();
// write to the channel
write(buffer);
/*
* If partial transfer, shift remainder down. If buffer is empty, same as doing clear()
*/
buffer.compact();
}
// EOF will leave buffer in fill state
buffer.flip();
// make sure the buffer is fully drained.
while (buffer.hasRemaining()) {
write(buffer);
}
}
int read(final ByteBuffer byteBuffer) {
try {
return this.source.read(byteBuffer);
} catch (final IOException exception) {
throw new IllegalStateException("Error reading from source channel", exception);
}
}
private void write(final ByteBuffer byteBuffer) {
try {
while (byteBuffer.hasRemaining()) {
this.destination.write(byteBuffer);
}
} catch (final IOException exception) {
throw new IllegalStateException("Error writing to destination channel", exception);
}
}
@Override
public void close() {
if (!this.shouldClose) {
return;
}
IOUtils.closeQuietly(this.source);
}
}