英文:
How to resume a interrupt download with RandomAccessFile?
问题
这段代码中,我想要使用RandomAccessFile来实现中断下载。以下是代码部分:
HttpGet httpget = HttpUtil.buildGet(URL);
httpget.setHeader("RANGE", "bytes=" + (position) + "-");
CloseableHttpResponse response = HttpClients.createDefault().execute(httpget);
HttpEntity entity = response.getEntity();
int totalLen = 0;
InputStream is = entity.getContent();
RandomAccessFile writeFile = new RandomAccessFile(desc, "rw");
writeFile.seek(position);
byte[] buf = new byte[65536];
totalLen = 0;
int len = is.read(buf);
while (len > 0) {
totalLen += len;
writeFile.write(buf);
len = is.read(buf);
}
response.close();
is.close();
writeFile.close();
HttpRequest返回206,下载成功完成,但是我得到了一个错误的文件。该文件比源文件要大得多,而且我无法打开它。这段代码有什么问题?如何使用RandomAccessFile来继续中断的下载?
注意:以上是你提供的代码的翻译部分,不包括问题和要求。如果你需要进一步的帮助,请随时提问。
英文:
I want to a interrupt download with RandomAccessFile. Here is the code
HttpGet httpget = HttpUtil.buildGet(URL)
httpget.setHeader("RANGE", "bytes=" + (position) + "-");
CloseableHttpResponse response = HttpClients.createDefault().execute(httpget)
HttpEntity entity = response.getEntity();
int totalLen = 0;
InputStream is = entity.getContent();
RandomAccessFile writeFile = new RandomAccessFile(desc, "rw");
writeFile.seek(position);
byte[] buf = new byte[65536];
totalLen = 0;
int len = is.read(buf);
while (len > 0) {
totalLen += len;
writeFile.write(buf);
len = is.read(buf);
}
response.close();
is.close();
writeFile.close();
The HttpRequest return 206 and the download success completed,But I get a wrong file,The file is much bigger than the source and I cant open it.
What's wrong with this code?And how to resume a interrupt download with RandomAccessFile?
答案1
得分: 2
> ```lang-none
> Accept-Ranges: bytes
> ETag: W/"243174107-1583744547157"
> Last-Modified: Mon, 09 Mar 2020 09:02:27 GMT
> Content-Range: bytes 32243658-243174106/243174107
> Content-Type: application/zip
> Content-Length: 210930449
> ```
请求指定了起始位置为 `32,243,658`,并下载了剩余的 `210,930,449` 字节,最终得到一个大小为 `243,174,107` 字节的文件。
实际上,文件的大小至少为 `243,204,042` 字节,即多了 `29,935` 字节,因为代码总是写入整个 `buffer`,即使缓冲区没有被完全读取。
很可能文件要比这大得多,因为数据是以较小的块通过网络传输的,所以在许多 `read()` 调用中缓冲区可能没有被填满到 `65,536` 字节。
`read()` 会返回一个 `len` 值,这是有原因的。你的代码应该是:
writeFile.write(buf, 0, len);
此外,你应该使用 try-with-resources,并且通常会内联 `read()` 调用,这样它就不会重复,例如代码应该是:
```java
int totalLen = 0;
try (RandomAccessFile writeFile = new RandomAccessFile(desc, "rw")) {
writeFile.seek(position); // 这里应该使用响应头中的值,而不是请求的值
try (InputStream is = entity.getContent()) {
byte[] buf = new byte[65536];
for (int len; (len = is.read(buf)) > 0; ) {
totalLen += len;
writeFile.write(buf, 0, len);
}
}
}
response.close();
<details>
<summary>英文:</summary>
From [comment][1]:
> ```lang-none
> Accept-Ranges: bytes
> ETag: W/"243174107-1583744547157"
> Last-Modified: Mon, 09 Mar 2020 09:02:27 GMT
> Content-Range: bytes 32243658-243174106/243174107
> Content-Type: application/zip
> Content-Length: 210930449
> ```
The request specified a starting position of `32,243,658`, and downloaded the remaining `210,930,449` bytes, ending up with a file with `243,174,107` bytes.
Well no, it ended up with a file with *at least* `243,204,042` bytes, i.e. `29,935` bytes too many, because the code always writes the **full** `buffer`, even if the buffer wasn't read in full.
It's very likely that the file is a lot bigger than that, because the data is coming over the network in smaller chunks, so it's likely that the buffer isn't filled with `65,536` bytes on many of the `read()` call.
`read()` returns a `len` value for a reason. Your code should be:
writeFile.write(buf, 0, len);
Also, you should use try-with-resources, and it's common to inline the `read()` call, so it's not repeated, e.g. code should be:
int totalLen = 0;
try (RandomAccessFile writeFile = new RandomAccessFile(desc, "rw")) {
writeFile.seek(position); // should use value from response header here, not requested value
try (InputStream is = entity.getContent()) {
byte[] buf = new byte[65536];
for (int len; (len = is.read(buf)) > 0; ) {
totalLen += len;
writeFile.write(buf, 0, len);
}
}
}
response.close();
[1]: https://stackoverflow.com/questions/61075227/how-to-resume-a-interrupt-download-with-randomaccessfile?noredirect=1#comment108052236_61075227
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论