我正在执行多个并行HTTP范围请求,并希望使用DigestInputStream
计算每个响应的MD5总和。我还想将HTTP流中的数据写入文件而不创建中间文件。因此,我使用FileChannel
并访问文件的区域。这基本上是一个Download Manager应用程序。
将HTTP流保存到文件中是有效的,但如果我尝试使用DigestInputStream
来动态计算MD5总和,则似乎永远不会读取DigestInputStream
。我可能遗漏了FileChannel
使用InputStream
的一些重要部分,我希望这很容易解决。
我也很高兴为优化提出建议,以实现上述目标。
这是实现下载任务的类
private class MultiHttpClientConnThread extends Thread {
private final Logger logger = Logger.getLogger(getClass());
private final CloseableHttpClient client;
private final HttpGet get;
private final String md5sum;
private File destinationFile;
public MultiHttpClientConnThread(final CloseableHttpClient client, final HttpGet get, final File destinationFile) {
this.client = client;
this.get = get;
this.destinationFile = destinationFile;
}
@Override
public final void run() {
try {
logger.debug("Thread Running: " + getName());
CloseableHttpResponse response = client.execute(get);
String contentRange = response.getFirstHeader("Content-Range").getValue();
Long startByte = Long.parseLong(contentRange.split("[ -]")[1]);
Long length = response.getEntity().getContentLength();
InputStream inputStream = response.getEntity().getContent();
ReadableByteChannel readableByteChannel;
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
DigestInputStream digestInputStream = new DigestInputStream(inputStream, messageDigest);
readableByteChannel = Channels.newChannel(digestInputStream);
RandomAccessFile randomAccessFile = new RandomAccessFile(destinationFile, "rw");
FileChannel fileChannel = randomAccessFile.getChannel();
fileChannel.transferFrom(readableByteChannel, startByte, length);
md5sum = Hex.encodeHexString(messageDigest.digest());
logger.info("Part MD5 sum: " + md5sum);
logger.debug("Thread Finished: " + getName());
response.close();
fileChannel.close();
randomAccessFile.close();
} catch (final ClientProtocolException ex) {
logger.error("", ex);
} catch (final IOException ex) {
logger.error("", ex);
} catch (final NoSuchAlgorithmException ex) {
logger.error("", ex);
}
}
}
这有点令人尴尬,因为代码似乎工作正常。问题在于我用于测试的上传文件。正如在How to create a repeatable incompressible fast InputStream in Java?中所要求的那样,我需要一个可重复的随机输入流,而我使用了来自here的那个,遗憾的是它似乎重复了一遍。因此,所有线程都具有相同的数据并提供相同的MD5总和,并且MD5总和看起来与空文件非常相似(但不完全相同)。
答案 0 :(得分:0)
在方法“transferFrom”中,第二个参数是在目的地中开始书写的位置。如果这是一个新文件,请尝试将其设置为零,而不是使用变量“startByte”(这是从源头开始读取的位置)。