使用 FileReader() 读取文件以从图像文件生成 md5 哈希字符串的正确方法?

Proper way to read a file using FileReader() to generate an md5 hash string from image files?

我目前正在执行此操作(请参阅下面的代码片段)以获取我正在上传的图像文件的 md5 哈希字符串(我将哈希用作 fileNames):

注意: 我正在使用 md5 包生成哈希(它已加载到代码段中)。

FileReader() 上有 4 种可用的方法来读取文件。他们似乎都产生了不错的结果。

在这种情况下我应该使用哪个?为什么?能不能也解释一下它们的区别?

function onFileSelect(e) {
  const file = e.target.files[0];
  const reader1 = new FileReader();
  const reader2 = new FileReader();
  const reader3 = new FileReader();
  const reader4 = new FileReader();
  
  reader1.onload = (event) => {
    const fileContent = event.target.result;
    console.log('Hash from "readAsText()": ');
    console.log(md5(fileContent));
  }
  
  reader2.onload = (event) => {
    const fileContent = event.target.result;
    console.log('Hash from "readAsBinaryString()": ');
    console.log(md5(fileContent));
  }
  
  reader3.onload = (event) => {
    const fileContent = event.target.result;
    console.log('Hash from "readAsArrayBuffer()": ');
    console.log(md5(fileContent));
  }
  
  reader4.onload = (event) => {
    const fileContent = event.target.result;
    console.log('Hash from "readAsDataURL()": ');
    console.log(md5(fileContent));
  }
  
  reader1.readAsText(file);
  reader2.readAsBinaryString(file);
  reader3.readAsArrayBuffer(file);
  reader4.readAsDataURL(file);
  
}
.myDiv {
  margin-bottom: 10px;
}
<script src="https://cdn.jsdelivr.net/npm/js-md5@0.7.3/src/md5.min.js"></script>
<div class="myDiv">Pick an image file to see the 4 hash results on console.log()</div>
<input type='file' onChange="onFileSelect(event)" accept='.jpg,.jpeg,.png,.gif' />

使用readAsArrayBuffer.

readAsBinaryString()readAsDataURL() 将使您的计算机完成比需要完成的工作更多的工作:

  1. 将 blob 读取为二进制流
  2. 转换为 UTF-16 / base64 字符串(记住字符串在 js 中是不可变的,你对它做的任何操作实际上都会在内存中创建一个副本)
  3. [传递给你的库]
  4. 转换为二进制字符串
  5. 处理数据

此外,您的库似乎不处理数据 URL,并且在 UTF-16 字符串上失败。

readAsText() 默认情况下会尝试将您的二进制数据解释为 UTF-8 文本序列,这对于像光栅图像这样的二进制数据来说非常糟糕:

// generate some binary data
document.createElement('canvas').toBlob(blob => {
  const utf8_reader = new FileReader();
  const bin_reader = new FileReader();
  let done = 0;
  utf8_reader.onload = bin_reader.onload = e => {
    if(++done===2) {
      console.log('same results: ', bin_reader.result === utf8_reader.result);
      console.log("utf8\n", utf8_reader.result);
      console.log("utf16\n", bin_reader.result);
    }
  }
  utf8_reader.readAsText(blob);
  bin_reader.readAsBinaryString(blob);
});

另一方面,

readAsArrayBuffer 只会按内存中的原样分配二进制数据。简单I/O,没有处理。
要操作这些数据,我们可以对这个二进制数据使用 TypedArrays 视图,它只是视图,不会产生任何开销。

如果您查看 the library you are using,他们无论如何都会将您的输入传递给这样的 Uint8Array 以进一步处理它。但是请注意,他们显然需要您传递此 ArrayBuffer 的 Uint8Array 视图,而不是直接传递裸 ArrayBuffer。