【发布时间】:2019-09-08 02:18:59
【问题描述】:
我想将一个已经分成数百个片段的大文件下载到一个文件中。
所以我将所有段的所有 URL-s 放在一个数组中,我将它手动分成 4 个部分,同时启动 4 个线程,然后在最后将它们合并为一个大文件。 我认为我可以改进我的代码的部分是我下载这些部分的部分。目标是打开文件一次,并将所有段附加到其中。 我也完全接受其他解决方案。
static void downloadFileSection(int begin, int end, int marker, String[] segmentURLs, String segID) {
try(var file = FileChannel.open(Path.of(segID + "_" + marker + ".seg"), WRITE, CREATE)){
var byteArrayHandler = BodyHandlers.ofByteArray();
IntStream.range(begin, end)
.forEach(index -> {
System.out.println("Downloading segment: " + index);
try {
//This is the part that I think is wrong. I shouldn't be creating a ByteBuffer every segment download.
//Main.sendNormalRequest is a method that sends a request using java 11-s HttpClient.send method.
file.write(ByteBuffer.wrap(Main.sendNormalRequest(segmentURLs[index], byteArrayHandler).body()));
} catch (IOException e) {
e.printStackTrace();
}
});
}catch (IOException e) {
e.printStackTrace();
}
}
【问题讨论】:
-
不清楚您的问题是什么。您是要尽量减少内存使用还是要并行处理?
-
我想知道是否有更好的方法将许多小文件下载到一个文件中,基本上是附加所有字节。谈到内存使用情况,我注意到 eclipse 内存分析器提到 HttpClient 正在保留对 ByteBuffers 的引用。
-
“最快”的方法是对小文件并行执行多个调用(例如,通过
ThreadPoolExecutor将它们排队),然后通过单个RandomAccessFile通过复制将部分写入目标文件从 HTTP 连接到 RAF-OutputStream 的 InputStream。这也应该具有最低的内存占用,因为您不会将文件完全加载到 RAM 中。 -
HttpClient 根据请求是通过 HTTPS 还是纯 HTTP 使用不同的策略。通常,它可能会将缓冲区切片转发给调用者代码以优化内存使用 - 这可能看起来好像它正在持有对字节缓冲区的引用,而它可能只是在等待下一个字节填充下一个切片。使用 HTTPS,在套接字和 SSL 引擎之间使用临时字节缓冲区:这些缓冲区通常被回收,并且 HttpClient 将保留对它们的引用,因为它们永远不会逃逸给调用者,但应该只有少数。跨度>
标签: java file httpclient nio segment