使用FileChannel时如何使用DigestInputStream计算MD5总和?

时间:2017-11-15 11:25:38

标签: java md5 filechannel

我正在执行多个并行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总和看起来与空文件非常相似(但不完全相同)。

1 个答案:

答案 0 :(得分:0)

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

transferFrom