首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

Java 檔案 MD5 驗證:正確計算檔案雜湊值的方法與陷阱

     編輯:J2ME

網路上常見將檔案完整讀入記憶體再計算 MD5 的做法,不僅記憶體效率差,且對大檔案可能導致 OOM。本文分析常見錯誤,提供正確的流式計算方法。

常見錯誤寫法

File file = new File("d:/1.dat");
FileInputStream fs = new FileInputStream(file);
BufferedInputStream bi = new BufferedInputStream(fs);
ByteArrayOutputStream bo = new ByteArrayOutputStream();
byte[] b = new byte[bi.available()];  // 危險:嘗試一次配置全檔案大小記憶體
int i;
while ((i = bi.read(b, 0, b.length)) != -1) {
    bo.write(b, 0, i);
}
bo.close();
System.out.print(Md5.MD5(new String(bo.toByteArray())));  // 錯誤:位元組轉字串再雜湊,結果不正確

三大關鍵問題

  1. 一次性配置巨大 byte[]:bi.available() 回傳剩餘位元組數,大檔案直接 OOM
  2. 位元組陣列轉 String 再雜湊:new String(byte[]) 依平台預設編碼解碼,可能導致資料損壞/不一致,MD5 必須直接處理原始位元組
  3. 未使用流式處理:應邊讀邊算,不需載入完整檔案

正確做法:流式計算 MD5

import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class FileMD5 {
    public static String calculate(File file) throws IOException, NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        try (FileInputStream fis = new FileInputStream(file);
             BufferedInputStream bis = new BufferedInputStream(fis)) {
            byte[] buffer = new byte[8192];  // 8KB 緩衝區
            int bytesRead;
            while ((bytesRead = bis.read(buffer)) != -1) {
                md.update(buffer, 0, bytesRead);  // 邊讀邊更新雜湊
            }
        }
        byte[] digest = md.digest();
        return bytesToHex(digest);
    }

    private static String bytesToHex(byte[] bytes) {
        char[] hexDigits = "0123456789abcdef".toCharArray();
        char[] result = new char[bytes.length * 2];
        for (int i = 0, k = 0; i < bytes.length; i++) {
            byte b = bytes[i];
            result[k++] = hexDigits[b >>> 4 & 0xF];
            result[k++] = hexDigits[b & 0xF];
        }
        return new String(result);
    }
}

關鍵點總結

  • 固定大小緩衝區(如 8KB),避免大檔案記憶體壓力
  • 直接對位元組更新 MessageDigest,無需轉字串
  • try-with-resources 確保串流正確關閉(Java 7+)
  • 十六進位轉換:每位元組拆高低 4 位元對應 hex 字元

補充:大檔案斷點續傳驗證

若需支援斷點驗證,可結合 RandomAccessFile 分段計算,或採用分塊雜湊樹(如 BT 的 piece hash),但核心原理相同:流式處理原始位元組。

正確的 MD5 計算不僅準確,更能優雅處理任意大小檔案,是檔案完整性驗證的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved