![](/img/trans.png)
[英]Is is possible to use NIO Selector for FileChannels in Java and/or Android?
[英]Java NIO FileChannels Track Progress
我正在嘗試從網上下載 mp4 文件。 我想異步執行並跟蹤進度,以便它可以顯示在進度條中。
我的代碼如下所示:
URLConnection con = url.openConnection();
ReadableByteChannel rbc = Channels.newChannel(con.getInputStream());
FileOutputStream fos = new FileOutputStream(file);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
創建一個使用 transferFrom 每次最多只能讀取 32KB 並遞增位置的循環是一種很好的做法,還是有更好的方法可以讓我跟蹤下載進度? 我怎么知道什么時候停止轉移?
我剛剛發現您可以通過 HTTP 標頭字段獲取文件大小:
con.getHeaderFields().get("Content-Length").get(0)
現在知道文件大小應該讓我能夠實現前面提到的循環。
InputStream in = con.getInputStream();
long fileSize = Long.parseLong(con.getHeaderFields().get("Content-Length").get(0));
FileOutputStream fos = new FileOutputStream(file);
for (long offset = 0; offset < fileSize; offset += transferBytesAtOnce) {
in.skip(offset);
ReadableByteChannel rbc = Channels.newChannel(in);
fos.getChannel().transferFrom(rbc, offset, transferBytesAtOnce);
System.out.println(offset + "/" + fileSize);
}
然而,正如我所料,這個解決方案的表現非常糟糕。 當將 transferBytesAtOnce 變量保持為低時,它只會下載非常慢。 使用高值時,它會取消下載。
編輯:Nvm,將跳過替換為
if (offset > 0) {
in.skip(transferBytesAtOnce);
}
它現在工作得更好一些,但仍然不如不跟蹤進度的解決方案快。
靈感來自這個我寫這個類
public class ReadableConsumerByteChannel implements ReadableByteChannel {
private final ReadableByteChannel rbc;
private final IntConsumer onRead;
private int totalByteRead;
public ReadableConsumerByteChannel(ReadableByteChannel rbc, IntConsumer onBytesRead) {
this.rbc = rbc;
this.onRead = onBytesRead;
}
@Override
public int read(ByteBuffer dst) throws IOException {
int nRead = rbc.read(dst);
notifyBytesRead(nRead);
return nRead;
}
protected void notifyBytesRead(int nRead){
if(nRead<=0) {
return;
}
totalByteRead += nRead;
onRead.accept(totalByteRead);
}
@Override
public boolean isOpen() {
return rbc.isOpen();
}
@Override
public void close() throws IOException {
rbc.close();
}
}
並通過像這樣包裹舊的來使用它
URLConnection con = new URL(url).openConnection();
int fileSize = con.getContentLength();
ReadableByteChannel rbc = Channels.newChannel(con.getInputStream());
ReadableConsumerByteChannel rcbc = new ReadableConsumerByteChannel(rbc,(b)->{
System.out.println("Read "+b +"/"+fileSize);
});
FileOutputStream fos = new FileOutputStream(file);
fos.getChannel().transferFrom(rcbc, 0, Long.MAX_VALUE);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.