使用 RandomAccessFile class 写入大文件
Write big files using RandomAccessFile class
我需要将大文件 (GB) 复制到另一个文件(容器)中,我想知道性能和 ram 使用情况。
像下面这样读取整个源文件:
RandomAccessFile f = new RandomAccessFile(origin, "r");
originalBytes = new byte[(int) f.length()];
f.readFully(originalBytes);
然后,像这样将所有内容复制到容器中:
RandomAccessFile f2 = new RandomAccessFile(dest, "wr");
f2.seek(offset);
f2.write(originalBytes, 0, (int) originalBytes.length);
一切都在记忆中,对吗?所以复制大文件会对内存产生影响,并可能导致 OutOfMemory 异常?
逐字节读取原始文件而不是完全读取原始文件更好吗?
在那种情况下,我应该如何进行?
提前谢谢你。
编辑:
根据 mehdi maick 的回答,我终于找到了解决方案:
我可以根据需要使用 RandomAccessFile 作为目标,并且因为 RandomAccessFile 有一个方法“getChannel” returns 一个 FileChannel 我可以将它传递给以下将执行复制的方法我想要的目标位置的文件(当时为 32KB):
public static void copyFile(File sourceFile, FileChannel destination, int position) throws IOException {
FileChannel source = null;
try {
source = new FileInputStream(sourceFile).getChannel();
destination.position(position);
int currentPosition=0;
while (currentPosition < sourceFile.length())
currentPosition += source.transferTo(currentPosition, 32768, destination);
} finally {
if (source != null) {
source.close();
}
}
}
读入blocks/chunks,例如一次 64k,使用 FileInputStream
和 FileOutputStream
.
如果你需要提高性能,你可以尝试使用线程,一个线程用于读取,另一个线程用于写入。
您也可以使用直接 NIO 缓冲区来提高性能。
参见例如A simple rule of when I should use direct buffers with Java NIO for network I/O?
尝试使用异步 nio Channel
public void copyFile(String src, String target) {
final String fileName = getFileName(src);
try (FileChannel from = (FileChannel.open(Paths.get(src), StandardOpenOption.READ));
FileChannel to = (FileChannel.open(Paths.get(target + "/" + fileName), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE))) {
transfer(from, to, 0l, from.size());
}
}
private String getFileName(final String src) {
File file = new File(src);
if (file.isFile()) {
return file.getName();
} else {
throw new RuntimeException("src is not a valid file");
}
}
private void transfer(final FileChannel from, final FileChannel to, long position, long size) throws IOException {
while (position < size) {
position += from.transferTo(position, Constants.TRANSFER_MAX_SIZE, to);
}
}
这将创建一个读写异步通道,并将数据从第一个高效地传输到后面。
我需要将大文件 (GB) 复制到另一个文件(容器)中,我想知道性能和 ram 使用情况。
像下面这样读取整个源文件:
RandomAccessFile f = new RandomAccessFile(origin, "r");
originalBytes = new byte[(int) f.length()];
f.readFully(originalBytes);
然后,像这样将所有内容复制到容器中:
RandomAccessFile f2 = new RandomAccessFile(dest, "wr");
f2.seek(offset);
f2.write(originalBytes, 0, (int) originalBytes.length);
一切都在记忆中,对吗?所以复制大文件会对内存产生影响,并可能导致 OutOfMemory 异常?
逐字节读取原始文件而不是完全读取原始文件更好吗? 在那种情况下,我应该如何进行? 提前谢谢你。
编辑:
根据 mehdi maick 的回答,我终于找到了解决方案: 我可以根据需要使用 RandomAccessFile 作为目标,并且因为 RandomAccessFile 有一个方法“getChannel” returns 一个 FileChannel 我可以将它传递给以下将执行复制的方法我想要的目标位置的文件(当时为 32KB):
public static void copyFile(File sourceFile, FileChannel destination, int position) throws IOException {
FileChannel source = null;
try {
source = new FileInputStream(sourceFile).getChannel();
destination.position(position);
int currentPosition=0;
while (currentPosition < sourceFile.length())
currentPosition += source.transferTo(currentPosition, 32768, destination);
} finally {
if (source != null) {
source.close();
}
}
}
读入blocks/chunks,例如一次 64k,使用 FileInputStream
和 FileOutputStream
.
如果你需要提高性能,你可以尝试使用线程,一个线程用于读取,另一个线程用于写入。
您也可以使用直接 NIO 缓冲区来提高性能。
参见例如A simple rule of when I should use direct buffers with Java NIO for network I/O?
尝试使用异步 nio Channel
public void copyFile(String src, String target) {
final String fileName = getFileName(src);
try (FileChannel from = (FileChannel.open(Paths.get(src), StandardOpenOption.READ));
FileChannel to = (FileChannel.open(Paths.get(target + "/" + fileName), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE))) {
transfer(from, to, 0l, from.size());
}
}
private String getFileName(final String src) {
File file = new File(src);
if (file.isFile()) {
return file.getName();
} else {
throw new RuntimeException("src is not a valid file");
}
}
private void transfer(final FileChannel from, final FileChannel to, long position, long size) throws IOException {
while (position < size) {
position += from.transferTo(position, Constants.TRANSFER_MAX_SIZE, to);
}
}
这将创建一个读写异步通道,并将数据从第一个高效地传输到后面。