FileChannel.transferFrom对于具有内存不足错误的较大文件失败 [英] FileChannel.transferFrom fails for larger files with Out of memory Error
问题描述
FileChannel.transferFrom(source,0,source.size())提供以下OutOfMemory异常.我了解由于文件较大而导致的内存问题.我们可以通过循环处理小块文件来解决它吗?
FileChannel.transferFrom(source, 0, source.size()) gives the following OutOfMemory exception, when trying to copy a file of size around 2GB. I understand the memory issue due to larger files. Can we solve it by coping the file in small chunks, in a loop?
01-22 17:27:03.365: W/System.err(28538): java.io.IOException: mmap failed: ENOMEM (Out of memory)
01-22 17:27:03.375: W/System.err(28538): at java.nio.MemoryBlock.mmap(MemoryBlock.java:119)
01-22 17:27:03.375: W/System.err(28538): at java.nio.FileChannelImpl.map(FileChannelImpl.java:249)
01-22 17:27:03.380: W/System.err(28538): at java.nio.FileChannelImpl.transferFrom(FileChannelImpl.java:381)
01-22 17:27:03.380: W/System.err(28538): at com.druva.inSync.util.InSyncIOUtils.copyFile(InSyncIOUtils.java:123)
01-22 17:27:03.380: W/System.err(28538): at com.druva.inSync.AsyncTasks.ProcessUploadTask.getFileItemForFile(ProcessUploadTask.java:102)
01-22 17:27:03.380: W/System.err(28538): at com.druva.inSync.AsyncTasks.ProcessUploadTask.processUploads(ProcessUploadTask.java:124)
01-22 17:27:03.380: W/System.err(28538): at com.druva.inSync.AsyncTasks.ProcessUploadTask.doInBackground(ProcessUploadTask.java:53)
01-22 17:27:03.380: W/System.err(28538): at com.druva.inSync.AsyncTasks.ProcessUploadTask.doInBackground(ProcessUploadTask.java:1)
01-22 17:27:03.380: W/System.err(28538): at android.os.AsyncTask$2.call(AsyncTask.java:287)
01-22 17:27:03.380: W/System.err(28538): at java.util.concurrent.FutureTask.run(FutureTask.java:234)
01-22 17:27:03.380: W/System.err(28538): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
01-22 17:27:03.380: W/System.err(28538): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
01-22 17:27:03.380: W/System.err(28538): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
01-22 17:27:03.380: W/System.err(28538): at java.lang.Thread.run(Thread.java:841)
01-22 17:27:03.385: W/System.err(28538): Caused by: libcore.io.ErrnoException: mmap failed: ENOMEM (Out of memory)
我尝试了以下代码:
for (long n = 0, s = source.size() >> 1; n < s;) {
Log.d("copy file", "inside for loop " + destination.size());
long c = destination.transferFrom(source, n, s - n);
n += c;
Log.d("copy file", "results: c=" + c + ", n=" + n);
}
但是它仅复制文件的前半部分...
but it copies only the first half of the file...
推荐答案
我在FileChannel.transferFrom上遇到了同样的问题,但是我什至偶尔看到文件小于512MB的ENOMEM错误.
I ran into the same issue with FileChannel.transferFrom, but I even occasionally saw the ENOMEM error with files less than 512MB.
这是我最终用来在较小的块中传输文件的代码:
Here's the code I ended up using to transfer the file in smaller blocks:
// Transfer file in 256MB blocks
final long blockSize = Math.min(268435456, sourceChannel.size());
long position = 0;
while (destinationChannel.transferFrom(sourceChannel, position, blockSize) > 0) {
position += blockSize;
}
transferFrom方法返回它成功复制的字节数.如果返回的数字大于零,则会复制整个块,因此请尝试复制另一个块.如果它什么也没复制,就完成了.
The transferFrom method returns the number of bytes it succeeded in copying. If it returns a number greater than zero, it copied the whole block, so attempt to copy another block. When it doesn't copy anything, you're done.
这篇关于FileChannel.transferFrom对于具有内存不足错误的较大文件失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!