【发布时间】:2017-11-15 11:25:38
【问题描述】:
我正在执行多个并行 HTTP 范围请求,并希望使用 DigestInputStream 计算每个响应的 MD5 总和。我还想将 HTTP 流中的数据写入文件而不创建中间文件。因此我使用FileChannel 并访问文件的区域。这基本上是一个下载管理器应用程序。
将 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 和看起来与空文件非常相似(但不相同)。
【问题讨论】:
-
你有没有用调试器检查一下发生了什么?
-
是的,我使用了调试器,我看到
digestInputStream的位置发生了变化。一切看起来都正确,但 MD5 和始终是空字符串的 MD5 和。 -
好吧,如果
DIS正在移动,它与频道无关。那是您正在运行的确切代码吗?从 IDE 复制粘贴?
标签: java md5 filechannel