Java InputStream:复制到同时计算hash

问题描述 投票:0回答:3

这是我的两个代码片段:

public class Uploader {

  private static final String SHA_256 = "SHA-256";

  public String getFileSHA2Checksum(InputStream fis) throws IOException {
    try {
      MessageDigest md5Digest = MessageDigest.getInstance(SHA_256);
      return getFileChecksum(md5Digest, fis);
    } catch (NoSuchAlgorithmException e) {
      return "KO";
    }
  }

  public void transferTo(InputStream fis) throws IOException {
    FileUtils.copyInputStreamToFile(fis, file2);
  }

我的代码使用这个类作为:

是否可以同时

copyToFile
calculateChecksum
杠杆
InputStream
是开放的?

java java-io java-nio
3个回答
3
投票

您可以使用

DigestInputStream
在从流中读取时计算哈希值。也就是说,您用
DigestInputStream
包装原始输入流并通读
DigestInputStream
.

或者,您可以使用

DigestOutputStream
在写入流时计算哈希。以类似的方式,您用
DigestOutputStream
包装目标输出流并写入
DigestOutputStream
.

一个快速而肮脏的例子:

var inputFile = Path.of("D:\\Development\\data\\testdata-csv\\customers-1000.csv");
var outputFile = Files.createTempFile("testoutput", ".dat");
var md = MessageDigest.getInstance("SHA-256");
try (var in = new DigestInputStream(Files.newInputStream(inputFile), md);
     var out = Files.newOutputStream(outputFile)) {
    in.transferTo(out);
} finally {
    Files.deleteIfExists(outputFile);
}

System.out.println(HexFormat.of().formatHex(md.digest()));

就您现有的代码而言,您可以执行以下操作:

public String transferAndHash(InputStream in) throws IOException {
    try {
        var md = MessageDigest.getInstance("SHA-256");
        try (var digestIn = new DigestInputStream(in, md)) {
            transferTo(digestIn);
        }
        return HexFormat.of().formatHex(md.digest());
    } catch (NoSuchAlgorithmException e) {
        // all recent Java versions are required to support SHA-256
        throw new AssertionError("Expected SHA-256 to be supported", e);
    }
}

(注意:

HexFormat
是在 Java 17 中引入的,如果您使用的是更早的版本,则需要一个替代版本。)


2
投票

这里是一个使用

DigestInputStream
的例子,基于Mark Rotteveel的建议(我喜欢):

Path input = Paths.get("input_file");
Path output = Paths.get("output_file");
MessageDigest algorithm = MessageDigest.getInstance("SHA-256");
try (InputStream is = Files.newInputStream(input);
     DigestInputStream hashingStream = new DigestInputStream(is, algorithm)) {
    Files.copy(hashingStream, output);
}
byte[] digest = algorithm.digest();
// this line uses Apache Commons Codec to show the hex representation of the byte[]
String hash = Hex.encodeHexString(digest);

1
投票

如果你想读取一次输入流,你可以手动从输入字符串中读取字节并自己写入你的文件。

    private static final String SHA_256 = "SHA-256";
    private static final int BUFFER = 1024;

    public String writeToFile(InputStream fis, File outputFile) throws IOException {
        try (var fout = new FileOutputStream(outputFile); fis) {
            MessageDigest md5Digest = MessageDigest.getInstance(SHA_256);
            var buffer = new byte[BUFFER];
            var bytesRead = 0;
            while (true) {
                bytesRead = fis.read(buffer);
                if (bytesRead < 0)
                    break;
                md5Digest.update(buffer, 0, bytesRead);
                fout.write(buffer, 0, bytesRead);
            }
            var checksume = md5Digest.digest();
            return Hex.encodeHexString(checksume);
        } catch (NoSuchAlgorithmException e) {
            return "KO";
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.