簡體   English   中英

如何使用javascript計算文件的md5哈希

[英]How to calculate md5 hash of a file using javascript

有沒有辦法在使用 Javascript 上傳到服務器之前計算文件的 MD5 哈希值?

雖然有 MD5 算法的JS 實現,但較舊的瀏覽器通常無法從本地文件系統讀取文件

我是在 2009 年寫的。那么新的瀏覽器呢?

使用支持FileAPI的瀏覽器,您可以讀取文件的內容- 用戶必須選擇它,無論是使用<input>元素還是拖放。 截至 2013 年 1 月,以下是主要瀏覽器的排列方式:

如何?

請參閱下面使用CryptoJSMD5 函數的Benny Neugebauer回答

我制作了一個實現增量 md5 的庫,以便有效地散列大文件。 基本上,您分塊讀取文件(以保持低內存)並逐步散列它。 您在自述文件中獲得了基本用法和示例。

請注意,您需要 HTML5 FileAPI,所以一定要檢查它。 test 文件夾中有一個完整的示例。

https://github.com/satazor/SparkMD5

使用CryptoJSMD5 函數HTML5 FileReader API計算 MD5 哈希值非常容易。 以下代碼片段顯示了如何讀取二進制數據並從已拖入瀏覽器的圖像中計算 MD5 哈希值:

var holder = document.getElementById('holder');

holder.ondragover = function() {
  return false;
};

holder.ondragend = function() {
  return false;
};

holder.ondrop = function(event) {
  event.preventDefault();

  var file = event.dataTransfer.files[0];
  var reader = new FileReader();

  reader.onload = function(event) {
    var binary = event.target.result;
    var md5 = CryptoJS.MD5(binary).toString();
    console.log(md5);
  };

  reader.readAsBinaryString(file);
};

我建議添加一些 CSS 以查看拖放區域:

#holder {
  border: 10px dashed #ccc;
  width: 300px;
  height: 300px;
}

#holder.hover {
  border: 10px dashed #333;
}

可以在此處找到有關拖放功能的更多信息: File API & FileReader

我在 Google Chrome 版本 32 中測試了示例。

HTML5 + spark-md5Q

假設您使用現代瀏覽器(支持 HTML5 文件 API),以下是計算大文件MD5 哈希的方法(它將計算可變塊的哈希)

 function calculateMD5Hash(file, bufferSize) { var def = Q.defer(); var fileReader = new FileReader(); var fileSlicer = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice; var hashAlgorithm = new SparkMD5(); var totalParts = Math.ceil(file.size / bufferSize); var currentPart = 0; var startTime = new Date().getTime(); fileReader.onload = function(e) { currentPart += 1; def.notify({ currentPart: currentPart, totalParts: totalParts }); var buffer = e.target.result; hashAlgorithm.appendBinary(buffer); if (currentPart < totalParts) { processNextPart(); return; } def.resolve({ hashResult: hashAlgorithm.end(), duration: new Date().getTime() - startTime }); }; fileReader.onerror = function(e) { def.reject(e); }; function processNextPart() { var start = currentPart * bufferSize; var end = Math.min(start + bufferSize, file.size); fileReader.readAsBinaryString(fileSlicer.call(file, start, end)); } processNextPart(); return def.promise; } function calculate() { var input = document.getElementById('file'); if (!input.files.length) { return; } var file = input.files[0]; var bufferSize = Math.pow(1024, 2) * 10; // 10MB calculateMD5Hash(file, bufferSize).then( function(result) { // Success console.log(result); }, function(err) { // There was an error, }, function(progress) { // We get notified of the progress as it is executed console.log(progress.currentPart, 'of', progress.totalParts, 'Total bytes:', progress.currentPart * bufferSize, 'of', progress.totalParts * bufferSize); }); }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/q.js/1.4.1/q.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/spark-md5/2.0.2/spark-md5.min.js"></script> <div> <input type="file" id="file"/> <input type="button" onclick="calculate();" value="Calculate" class="btn primary" /> </div>

您需要使用 FileAPI。 它適用於最新的 FF 和 Chrome,但不適用於 IE9。 獲取上面建議的任何 md5 JS 實現。 我已經嘗試過這個並放棄了它,因為 JS 太慢(大圖像文件需要幾分鍾)。 如果有人使用類型化數組重寫 MD5,可能會重新訪問它。

代碼看起來像這樣:

HTML:     
<input type="file" id="file-dialog" multiple="true" accept="image/*">

JS (w JQuery)

$("#file-dialog").change(function() {
  handleFiles(this.files);
});

function handleFiles(files) {
    for (var i=0; i<files.length; i++) {
        var reader = new FileReader();
        reader.onload = function() {
        var md5 = binl_md5(reader.result, reader.result.length);
            console.log("MD5 is " + md5);
        };
        reader.onerror = function() {
            console.error("Could not read the file");
        };
        reader.readAsBinaryString(files.item(i));
     }
 }

除了不可能在 JS 中獲得文件系統訪問權限之外,我根本不會信任客戶端生成的校驗和。 因此在任何情況下都必須在服務器上生成校驗和。 – 托馬拉克 2009 年 4 月 20 日 14:05

這在大多數情況下是無用的。 您希望在客戶端計算 MD5,以便您可以將其與在服務器端重新計算的代碼進行比較,如果它們不同,則得出上傳出錯的結論。 我需要在處理大型科學數據文件的應用程序中這樣做,其中接收未損壞的文件是關鍵。 我的案例很簡單,因為用戶已經從他們的數據分析工具中計算出 MD5,所以我只需要通過文本字段向他們詢問。

以下代碼段顯示了一個示例,該示例可以在讀取和散列文件時以 400 MB/s 的吞吐量存檔。

它使用了一個名為hash-wasm的庫,它基於 WebAssembly 並且比僅使用 js 的庫更快地計算哈希。 截至 2020 年,所有現代瀏覽器都支持 WebAssembly。

 const chunkSize = 64 * 1024 * 1024; const fileReader = new FileReader(); let hasher = null; function hashChunk(chunk) { return new Promise((resolve, reject) => { fileReader.onload = async(e) => { const view = new Uint8Array(e.target.result); hasher.update(view); resolve(); }; fileReader.readAsArrayBuffer(chunk); }); } const readFile = async(file) => { if (hasher) { hasher.init(); } else { hasher = await hashwasm.createMD5(); } const chunkNumber = Math.floor(file.size / chunkSize); for (let i = 0; i <= chunkNumber; i++) { const chunk = file.slice( chunkSize * i, Math.min(chunkSize * (i + 1), file.size) ); await hashChunk(chunk); } const hash = hasher.digest(); return Promise.resolve(hash); }; const fileSelector = document.getElementById("file-input"); const resultElement = document.getElementById("result"); fileSelector.addEventListener("change", async(event) => { const file = event.target.files[0]; resultElement.innerHTML = "Loading..."; const start = Date.now(); const hash = await readFile(file); const end = Date.now(); const duration = end - start; const fileSizeMB = file.size / 1024 / 1024; const throughput = fileSizeMB / (duration / 1000); resultElement.innerHTML = ` Hash: ${hash}<br> Duration: ${duration} ms<br> Throughput: ${throughput.toFixed(2)} MB/s `; });
 <script src="https://cdn.jsdelivr.net/npm/hash-wasm"></script> <!-- defines the global `hashwasm` variable --> <input type="file" id="file-input"> <div id="result"></div>

要獲取文件的哈希值,有很多選項。 通常問題是獲取大文件的哈希值真的很慢。

我創建了一個獲取文件散列的小庫,文件開頭為 64kb,文件結尾為 64kb。

現場示例: http : //marcu87.github.com/hashme/和圖書館: https : //github.com/marcu87/hashme

互聯網上有幾個腳本可以創建 MD5 哈希。

來自 webtoolkit 的一個很好, http://www.webtoolkit.info/javascript-md5.html

雖然,我不相信它可以訪問本地文件系統,因為訪問是有限的。

希望您現在已經找到了一個好的解決方案。 如果沒有,下面的解決方案是基於js-spark-md5的ES6 promise實現

import SparkMD5 from 'spark-md5';

// Read in chunks of 2MB
const CHUCK_SIZE = 2097152;

/**
 * Incrementally calculate checksum of a given file based on MD5 algorithm
 */
export const checksum = (file) =>
  new Promise((resolve, reject) => {
    let currentChunk = 0;
    const chunks = Math.ceil(file.size / CHUCK_SIZE);
    const blobSlice =
      File.prototype.slice ||
      File.prototype.mozSlice ||
      File.prototype.webkitSlice;
    const spark = new SparkMD5.ArrayBuffer();
    const fileReader = new FileReader();

    const loadNext = () => {
      const start = currentChunk * CHUCK_SIZE;
      const end =
        start + CHUCK_SIZE >= file.size ? file.size : start + CHUCK_SIZE;

      // Selectively read the file and only store part of it in memory.
      // This allows client-side applications to process huge files without the need for huge memory
      fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
    };

    fileReader.onload = e => {
      spark.append(e.target.result);
      currentChunk++;

      if (currentChunk < chunks) loadNext();
      else resolve(spark.end());
    };

    fileReader.onerror = () => {
      return reject('Calculating file checksum failed');
    };

    loadNext();
  });

使用當前的 HTML5 應該可以計算二進制文件的 md5 哈希值,但我認為之前的步驟是將二進制數據 BlobBuilder 轉換為字符串,我正在嘗試執行此步驟:但尚未成功。

這是我嘗試過的代碼: Converting a BlobBuilder to string, in HTML5 Javascript

我不相信 javascript 中有一種方法可以訪問文件上傳的內容。 因此,您無法查看文件內容來生成 MD5 總和。

但是,您可以將文件發送到服務器,然后服務器可以發送回 MD5 總和或將文件內容發送回 .. 但這需要大量工作,對於您的目的來說可能不值得。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM