【问题标题】:How to use DigestInputStream to calculate MD5 sum when using FileChannel?使用 FileChannel 时如何使用 DigestInputStream 计算 MD5 和?
【发布时间】: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


【解决方案1】:

在“transferFrom”方法中,第二个参数是在destination中开始写入的位置。如果这是一个新文件,请尝试将其设置为零,而不是使用变量“startByte”(这是从源开始读取的位置)。

transferFrom

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-02
    • 2019-07-30
    • 1970-01-01
    • 2022-09-23
    • 2011-03-26
    • 1970-01-01
    • 2010-10-20
    • 2016-06-16
    相关资源
    最近更新 更多