You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中不解压tar.gz文件获取内部文件MD5哈希的方法

无需解压tar.gz文件获取内部图片MD5哈希值的方法?

我有一个包含大量图片的大型tar.gz文件,需要获取每张图片的MD5哈希值。现有代码可正常处理普通文件夹及图片,但无法获取tar.gz文件内图片的哈希值。尝试直接访问tar.gz内的图片路径时出现以下异常:

Caused by: java.nio.file.FileSystemException: /Users/myuser/old/file.tar.gz/1.jpg: Not a directory
    at sun.nio.fs.UnixException.translateToIOException(UnixException.java:91)
    at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
    at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
    at sun.nio.fs.UnixFileAttributeViews$Basic.readAttributes(UnixFileAttributeViews.java:55)
    at sun.nio.fs.UnixFileSystemProvider.readAttributes(UnixFileSystemProvider.java:144)
    at java.nio.file.Files.readAttributes(Files.java:1737)
    at java.nio.file.FileTreeWalker.getAttributes(FileTreeWalker.java:219)
    at java.nio.file.FileTreeWalker.visit(FileTreeWalker.java:276)
    at java.nio.file.FileTreeWalker.walk(FileTreeWalker.java:322)
    at java.nio.file.FileTreeIterator.<init>(FileTreeIterator.java:72)
    at java.nio.file.Files.walk(Files.java:3574)
    at java.nio.file.Files.walk(Files.java:3625)
    at com.example.demo.ImageDeduplication.listFiles(ImageDeduplication.java:78)
    at com.example.demo.SparkSQL.lambda$1(SparkSQL.java:82)
    at org.apache.spark.sql.UDFRegistration.$anonfun$register$352(UDFRegistration.scala:775)
    ... 17 more

当前使用的代码如下:

public static String digestAndBuildImageEntry(Path filePath) throws NoSuchAlgorithmException {
            try (InputStream is = Files.newInputStream(filePath);
                    BufferedInputStream buffered = new BufferedInputStream(is)) {

                byte[] data = Files.readAllBytes(filePath);
                byte[] hashByte = MessageDigest.getInstance("MD5").digest(data);

                String hash = hashByte.toString();
                return hash;
            } catch (Exception ex) {
                return null;
            }
        }

路径测试情况

  • 正常工作的路径:
    • /Users/myuser/old/1.jpg - 可获取哈希
    • /Users/myuser/old/ - 可遍历获取文件夹内所有文件
    • /Users/myuser/old/file.tar.gz - 可获取整个tar.gz文件的哈希
  • 无法正常工作的路径:
    • /Users/myuser/old/file.tar.gz/1.jpg - 提示“Not a directory”

解决方案

可以不用解压tar.gz文件,直接通过流读取内部文件内容计算MD5。推荐使用Apache Commons Compress库处理tar.gz文件,它支持直接读取归档内的条目,无需写入磁盘。

步骤1:引入依赖(Maven)

在pom.xml中添加依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-compress</artifactId>
    <version>1.24.0</version> <!-- 使用最新稳定版本 -->
</dependency>

步骤2:编写处理代码

核心思路是打开tar.gz的输入流,遍历每个归档条目,判断是否为图片文件,然后通过流分块计算MD5(避免一次性加载大文件到内存):

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Set;

public class TarGzImageHasher {
    // 定义需要处理的图片后缀
    private static final Set<String> IMAGE_EXTENSIONS = Set.of("jpg", "jpeg", "png", "gif", "bmp");

    public static void processTarGz(Path tarGzPath) throws IOException, NoSuchAlgorithmException {
        try (InputStream fis = new FileInputStream(tarGzPath.toFile());
             BufferedInputStream bis = new BufferedInputStream(fis);
             GzipCompressorInputStream gzis = new GzipCompressorInputStream(bis);
             TarArchiveInputStream tais = new TarArchiveInputStream(gzis)) {

            TarArchiveEntry entry;
            while ((entry = tais.getNextTarEntry()) != null) {
                // 跳过目录和非图片文件
                if (entry.isDirectory() || !isImageFile(entry.getName())) {
                    continue;
                }

                // 计算当前图片条目的MD5
                String md5Hash = calculateMd5(tais);
                System.out.printf("文件: %s, MD5: %s%n", entry.getName(), md5Hash);
            }
        }
    }

    private static boolean isImageFile(String fileName) {
        int dotIndex = fileName.lastIndexOf('.');
        if (dotIndex == -1) {
            return false;
        }
        String extension = fileName.substring(dotIndex + 1).toLowerCase();
        return IMAGE_EXTENSIONS.contains(extension);
    }

    private static String calculateMd5(InputStream inputStream) throws NoSuchAlgorithmException, IOException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] buffer = new byte[8192]; // 8KB缓冲,适合大文件处理
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            md.update(buffer, 0, bytesRead);
        }
        byte[] hashBytes = md.digest();
        // 将字节数组转为标准十六进制字符串(修正原代码中byte[]直接toString的错误)
        StringBuilder sb = new StringBuilder();
        for (byte b : hashBytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    // 测试入口
    public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
        Path tarGzPath = Path.of("/Users/myuser/old/file.tar.gz");
        processTarGz(tarGzPath);
    }
}

关键说明

  1. 内存优化:用8KB缓冲分块读取文件内容,避免一次性加载大型图片到内存引发溢出。
  2. 哈希值修正:原代码中hashByte.toString()返回的是对象地址,这里转为标准十六进制哈希字符串。
  3. 文件过滤:通过后缀名筛选图片文件,跳过目录和非图片条目,提升处理效率。

内容的提问来源于stack exchange,提问作者Anonymous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 17:45:37