【问题标题】:Download already segmented files with NIO - Java 11使用 NIO 下载已分段的文件 - Java 11
【发布时间】: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


【解决方案1】:

您可以使用BodyHandlers.ofPublisher() 来获取Publisher<List<ByteBuffer>>。然后,如果状态为 200 OK,则提供并订阅您自己的 Flow.Subscriber<List<ByteBuffer>> 实现并将字节写入文件,因为它们来自 onNext(...) 方法。如果这些字节代表文本,那么您可能需要注意字符编码/转码,特别是如果您需要使用与服务器发送的编码不同的编码(通常是 UTF-8)来编写文件。

【讨论】:

    猜你喜欢
    • 2021-08-17
    • 2019-03-24
    • 2018-12-25
    • 1970-01-01
    • 1970-01-01
    • 2014-08-09
    • 1970-01-01
    • 1970-01-01
    • 2012-01-14
    相关资源
    最近更新 更多