Java NIO 从输入流读取大文件

3

我希望读取一个大的输入流并将其作为文件返回。因此,我需要拆分输入流(或者我应该在多个线程中读取输入流)。我该如何做?我正在尝试这样做:

    URL url = new URL("path");
    URLConnection connection = url.openConnection();
    int fileSize = connection.getContentLength();

    InputStream is = connection.getInputStream();
    ReadableByteChannel rbc1 = Channels.newChannel(is);
    ReadableByteChannel rbc2 = Channels.newChannel(is);

    FileOutputStream fos = new FileOutputStream("file.ext");

    FileChannel fileChannel1 = fos.getChannel();
    FileChannel fileChannel2 = fos.getChannel();
    fileChannel1.transferFrom(rbc1, 0, fileSize/2);
    fileChannel2.transferFrom(rbc2, fileSize/2, fileSize/2);

    fos.close();

但这不会影响性能。

1
不行,千万别试图并行处理流!流天生是需要按顺序处理的。如果你试图在并行环境下操作它们,那么你最多只会使事情变得更慢,但更有可能是完全毁掉数据。 - John Bollinger
2
此外,如果数据是通过网络传输,则瓶颈几乎肯定是网络。如果不是这样,那么它将是您正在写入的本地磁盘。当您只是从源到汇移动字节时,接收程序内部的数据处理不会成为问题。 - John Bollinger
基本前提是错误的。您无法同时从网络流的两个位置读取数据。只有一个流。 - user207421
@JohnBollinger 当使用TCP时,通过同一网络传输两个流可能比一个流更快(这是否公平有争议)。 - eckes
1
@eckes,当然可以使用两条流。OP只有一条流,这也是他提出问题的情况。不清楚是否可以在服务器上安排传输他的一个文件的双流设置。 - John Bollinger
我想读取一个大的InputStream,并将其作为文件返回。所以我需要分割... 非序言 - user207421
2个回答

2

您可以打开多个(HTTP)连接到同一资源(URL),但使用HTTP的Range: Header使每个流从另一个点开始读取。这实际上可以加速数据传输,特别是当高延迟是问题时。您不应该过分利用并行性,要注意它会给服务器增加额外的负载。

connection1.setRequestProperty("Range", "bytes=0-" + half);
connection2.setRequestProperty("Range", "bytes=" + half+1 +"-");

这也可以用于恢复下载。需要服务器支持。可以使用 Accept-Ranges: bytes 来声明,但不一定需要。请准备好第一个连接可能会返回整个请求的实体(状态200与206相对)。

您需要在单独的线程中读取URLConnections的输入流,因为这是阻塞IO(不确定NIO包装是否有帮助)。


-1

您可以使用每个通道的position(long)方法开始读取。

请查看此内容。

http://tutorials.jenkov.com/java-nio/file-channel.html#filechannel-position

此外,如果您想要部分下载文件,

Parallel Downloading

To download multiple parts of a file parallelly, we need to create multiple threads. Each thread is implemented similarly to the simple thread above, except that it needs to download only a part of the downloaded file. To do that, the HttpURLConnection or its super class URLConnection provides us method setRequestProperty to set the range of the bytes we want to download.

// open Http connection to URL
HttpURLConnection conn = (HttpURLConnection)mURL.openConnection();

// set the range of byte to download
String byteRange = mStartByte + "-" + mEndByte;
conn.setRequestProperty("Range", "bytes=" + byteRange);

// connect to server
conn.connect();

这对你会很有帮助。

我在这里找到了答案,你可以查看完整的教程。

http://luugiathuy.com/2011/03/download-manager-java/


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - user207421
有时我不明白为什么有些回答要遮遮掩掩的。这个人想要一个并行下载的答案。而你只是说了“不行”。请积极地帮助寻找答案的人。 - Afsin Buyuksarac
注释没有起作用?抱歉,但你需要更多的支持。 - Afsin Buyuksarac
我不知道“注释没有显示效果?”意味着什么,或者它究竟在哪里说我“必须更支持”。你不能支持一个毫无意义的想法。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接