1.1.2.3 2023-11-19 13:27 采纳率: 0%
浏览 11

Java怎么实现大文件切片多线程MD5校验呢?

Java怎么实现大文件切片多线程MD5计算呢?

最近在做文件的校验,一个1.5G的文件MD5计算结果耗时大概在5s左右,后续优化到下面的版本后,发现再怎么优化结果都是在3s左右。

现在在想能不能对文件进行切片,采取多线程分开计算的形式来计算MD5值。
我也试了几个版本,但是发现计算的结果和cmd计算的结果不一致。

certutil -hashfile <filepath> MD5

所以想提问一下:Java怎么实现大文件切片多线程MD5计算呢?

(CPU是i5-11600K)

下面是我写的单线程MD5计算方法

    public static String getFileMD5 (File file) {
        try {
            Path path = file.toPath();
            FileChannel fileChannel = FileChannel.open(path);

            MessageDigest MD5 = MessageDigest.getInstance("MD5");
            ByteBuffer buffer = ByteBuffer.allocate(8192);

            while(fileChannel.read(buffer) != -1) {
                buffer.flip();
                MD5.update(buffer);
                buffer.clear();
            }

            fileChannel.close();
            return Hex.encodeHexString(MD5.digest());
        } catch (IOException | NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }
  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-11-20 00:35
    关注

    【以下回答由 GPT 生成】

    问题分析: 根据问题描述,需要解决以下两个问题: 1. 如何在Java中实现对大文件的切片和多线程MD5校验。 2. 如何优化单线程MD5计算方法。

    解决方案: 1. 大文件切片和多线程MD5校验的实现: - 首先,将大文件切分成多个小文件块,每个文件块的大小可以根据实际情况确定。 - 接下来,创建一个线程池,并将每个小文件块的MD5计算任务提交到线程池中。 - 每个线程计算完MD5值后,将结果存储到一个线程安全的数据结构中,比如ConcurrentHashMap。 - 最后,等待所有线程完成计算,并将所有小文件块的MD5值合并为一个整体的MD5值。

    下面是一个简单的示例代码:

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.math.BigInteger;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class FileMD5Checker {
        private static final int THREAD_POOL_SIZE = 4; // 线程池大小,可根据实际情况进行调整
    
        public static void main(String[] args) {
            File file = new File("path/to/large/file"); // 待计算MD5的大文件
    
            try {
                byte[] fileData = readFile(file);
    
                // 切分文件并计算MD5
                ConcurrentHashMap<String, byte[]> md5Map = computeMD5WithMultiThread(fileData);
    
                // 合并MD5值
                byte[] mergedMD5 = mergeMD5(md5Map);
    
                // 将MD5值转换为字符串
                String md5Str = new BigInteger(1, mergedMD5).toString(16);
    
                // 输出MD5值
                System.out.println("MD5: " + md5Str);
            } catch (IOException | NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
    
        private static byte[] readFile(File file) throws IOException {
            byte[] data = new byte[(int) file.length()];
            try (FileInputStream fis = new FileInputStream(file)) {
                fis.read(data);
            }
            return data;
        }
    
        private static ConcurrentHashMap<String, byte[]> computeMD5WithMultiThread(byte[] fileData)
                throws NoSuchAlgorithmException {
            ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
            ConcurrentHashMap<String, byte[]> md5Map = new ConcurrentHashMap<>();
    
            int blockSize = fileData.length / THREAD_POOL_SIZE;
            for (int i = 0; i < THREAD_POOL_SIZE; i++) {
                int start = i * blockSize;
                int end = (i == THREAD_POOL_SIZE - 1) ? fileData.length : (i + 1) * blockSize;
                byte[] blockData = new byte[end - start];
                System.arraycopy(fileData, start, blockData, 0, end - start);
    
                executorService.submit(new MD5Calculator(blockData, md5Map, i));
            }
    
            executorService.shutdown();
            while (!executorService.isTerminated()) {
                // 等待线程池中所有线程执行完成
            }
    
            return md5Map;
        }
    
        private static byte[] mergeMD5(ConcurrentHashMap<String, byte[]> md5Map) throws NoSuchAlgorithmException {
            MessageDigest md5Digest = MessageDigest.getInstance("MD5");
            for (byte[] md5 : md5Map.values()) {
                md5Digest.update(md5);
            }
            return md5Digest.digest();
        }
    
        private static class MD5Calculator implements Callable<Void> {
            private final byte[] data;
            private final ConcurrentHashMap<String, byte[]> md5Map;
            private final int index;
    
            public MD5Calculator(byte[] data, ConcurrentHashMap<String, byte[]> md5Map, int index) {
                this.data = data;
                this.md5Map = md5Map;
                this.index = index;
            }
    
            @Override
            public Void call() throws Exception {
                MessageDigest md5Digest = MessageDigest.getInstance("MD5");
                byte[] md5 = md5Digest.digest(data);
    
                String key = "block-" + index;
                md5Map.put(key, md5);
    
                return null;
            }
        }
    }
    
    1. 单线程MD5计算方法的优化:
    2. 可以考虑通过使用更快速的MD5算法库来替代Java标准库中的MessageDigest实现,比如Apache的Commons Codec库中的DigestUtils.md5Hex()方法。
    3. 另外,还可以尝试使用更高效的数据读取方式,比如使用java.nio.file.Files.readAllBytes()方法一次性读取整个文件而不是逐字节读取。
    4. 同时,可以考虑将字节数组转换为java.nio.ByteBuffer,进一步提升计算速度。

    以下是示例代码:

    import org.apache.commons.codec.digest.DigestUtils;
    
    import java.io.File;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.file.Files;
    import java.security.NoSuchAlgorithmException;
    
    public class FileMD5Checker {
        public static void main(String[] args) {
            File file = new File("path/to/file");
    
            try {
                byte[] data = Files.readAllBytes(file.toPath());
    
                // 使用Apache Commons Codec库中的DigestUtils计算MD5值
                String md5Hex = DigestUtils.md5Hex(data);
    
                // 输出MD5值
                System.out.println("MD5: " + md5Hex);
            } catch (IOException | NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
    }
    

    这些优化措施可以提升MD5计算速度,从而更好地满足计算大文件的要求.

    请注意,以上代码仅为示例,真正的实现可能需要根据具体情况进行调整和扩展。



    【相关推荐】



    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    评论

报告相同问题?

问题事件

  • 修改了问题 11月19日
  • 创建了问题 11月19日

悬赏问题

  • ¥15 模电中二极管,三极管和电容的应用
  • ¥15 关于模型导入UNITY的.FBX: Check external application preferences.警告。
  • ¥15 气象网格数据与卫星轨道数据如何匹配
  • ¥100 java ee ssm项目 悬赏,感兴趣直接联系我
  • ¥15 微软账户问题不小心注销了好像
  • ¥15 x264库中预测模式字IPM、运动向量差MVD、量化后的DCT系数的位置
  • ¥15 curl 命令调用正常,程序调用报 java.net.ConnectException: connection refused
  • ¥20 关于web前端如何播放二次加密m3u8视频的问题
  • ¥15 使用百度地图api 位置函数报错?
  • ¥15 metamask如何添加TRON自定义网络