javascript - JS - 如何计算二进制数据的 MD5

标签 javascript utf-8 google-chrome-extension binary fileapi

编辑:将标题从“JS File API - 写入和读取UTF-8数据不一致”更改为反射(reflect)实际问题。

我有一些二进制内容需要计算 MD5。内容是 WARC 文件,这意味着它包含文本和编码图像。为了避免文件保存时出现错误,我将所有数据转换并存储在 arrayBuffers 中。所有数据都放入 UInt8Array 中以将其转换为 UTF-8。

为了测试,我的第一次尝试是使用 saveAs 库来保存 Chrome 扩展程序中的文件。这意味着我使用了一个 blob 对象来传递给该方法并创建文件。

var b = new Blob(arrayBuffers, {type: "text/plain;charset=utf-8"});
saveAs(b,'name.warc');

我还没有找到从 Blob 对象计算 MD5 的工具,所以我所做的是使用 FileReader 将 blob 文件读取为二进制数据,并然后使用MD5工具(我使用cryptoJS以及faultylabs的工具)来计算结果。

f = new FileReader();
f.readAsBinaryString(b);
f.onloadend = function(a){
    console.log( 'Original file checksum: ', faultylabs.MD5(this.result) );
}

资源(图像)直接以arraybuffer格式下载,因此我不需要转换它们。

结果是错误的,这意味着从代码中检查 MD5 和从我保存在本地计算机上的文件中检查 MD5 给出了 2 个不同的结果。作为文本读取,显然会抛出错误。

我发现的解决方法包括使用文件系统 API 将 blob 对象写入磁盘,然后将其作为二进制数据读回,计算 MD5,然后将检索到的文件保存为 WARC 文件(不是直接 blob 对象,而是这个文件的“刷新”版本)。 在这种情况下,计算出的 MD5 很好(我在 warc 文件的“刷新”版本上计算它),但是当我使用“刷新”warc 存档启动 WARC 重播实例时,它会抛出错误 - 而使用原始文件时,我会遇到错误。没有任何问题(但是MD5不正确)。

var fd = new FormData();

// To compute the md5 hash and to have it correct on the server side, we need to write the file to the system, read it back and then calculate the md5 value.
// We need to send this version of the warc file to the server as well.
window.requestFileSystem  = window.requestFileSystem || window.webkitRequestFileSystem;

function computeWARC_MD5(callback,formData) {
    window.requestFileSystem(window.TEMPORARY, b.size, onInitFs);
    function onInitFs(fs) {
        fs.root.getFile('warc.warc', {create: true}, function(fileEntry) {
            fileEntry.createWriter(function(fileWriter) {
                fileWriter.onwriteend = function(e) {
                  readAndMD5();
                };
                fileWriter.onerror = function(e) {
                  console.error('Write failed: ' + e.toString());
                };
                fileWriter.write(b);
            });
        });

        function readAndMD5() {
            fs.root.getFile('warc.warc', {}, function(fileEntry) {
                fileEntry.file( function(file) {
                    var reader = new FileReader();
                    reader.onloadend = function(e) {
                        var warcMD5 = faultylabs.MD5( this.result );
                        console.log(warcMD5);
                        var g = new Blob([this.result],{type: "text/plain;charset=utf-8"});
                        saveAs(g, o_request.file);
                        formData.append('warc_file', g)
                        formData.append('warc_checksum_md5', warcMD5.toLowerCase());
                        callback(formData);
                    };
                    reader.readAsBinaryString(file);
                });
            });
        }
    }
}

function uploadData(formData) {
    // upload
    $.ajax({
        type: 'POST',
        url: server_URL_upload,
        data: fd,
        processData: false,
        contentType: false,
        // [SPECS] fire a progress event named progress at the XMLHttpRequestUpload object about every 50ms or for every byte transmitted, whichever is least frequent
        xhrFields: {
            onprogress: function (e) {
                if (e.lengthComputable) {
                    console.log(e.loaded / e.total * 100 + '%');
                }
            }
        }
    }).done(function(data) {
       console.log('done uploading!');
       //displayMessage(port_to_page, 'Upload finished!', 'normal')
       //port_to_page.postMessage( { method:"doneUpload" } );
    });
}
computeWARC_MD5(uploadData, fd);
saveAs(b, 'warc.warc');

谁能解释一下为什么会出现这种差异?将我正在处理的所有对象视为二进制数据(存储、读取)时我缺少什么?

最佳答案

基本上,我尝试了另一条路线,并将 blob 文件转换回 arraybuffer 并计算 MD5。此时,文件的 MD5 和数组缓冲区的 MD5 是相同的。

var b = new Blob(arrayBuffers, {type: "text/plain;charset=utf-8"});
            var blobHtml = new Blob( [str2ab(o_request.main_page_html)], {type: "text/plain;charset=utf-8"} );

f = new FileReader();
f.readAsArrayBuffer(b);
f.onloadend = function(a){
  var warcMD5 = faultylabs.MD5(this.result);
  var fd = new FormData();
  fd.append('warc_file', b)
  fd.append('warc_checksum_md5', warcMD5.toLowerCase());

  uploadData(fd);
}

我猜二进制字符串和缓冲区数组的结果是不同的,这就是 MD5 不一致的原因。

关于javascript - JS - 如何计算二进制数据的 MD5,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25148246/

相关文章:

javascript - 服务器没有收到 Angular http 请求

Javascript 幻灯片 - 更改 div 的背景图像

javascript - jQuery <select> 选项仅启用一些选项

mysql - 使用 Codeigniter 对 utf8_bin 表按字母顺序排序

c++ - 从 std::string 中提取(第一个)UTF-8 字符

javascript - Chrome 扩展 - 如何仅使用名称字段而不是 id 将字段表单聚焦到当前页面

javascript - 声明对象数组

c - 如何最好地处理 Windows 的 16 位 wchar_t 丑陋?

google-chrome-extension - 不要在 Chrome 扩展程序中使用 Google Analytics

background - 在内容脚本中获取背景变量值