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?
From comment:
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();