读取 javascript 中的本地二进制文件并转换为 base64

Reading a local binary file in javascript and converting to base64

我有一个 local 站点,它使用 Javascript 浏览我机器上的文件。这不是 NodeJS 问题。我一直在读取本地文件系统上的 binary 文件并将它们转换为 base64。我遇到的问题是有不可打印的字符。我从 javascript 获得的输出与 Linux 中的 base64 命令行工具不同。

一个示例文件,我们可以用于这个问题,是用 head -c 8 /dev/random > random 生成的——它只是一些写入文件的二进制废话。在此示例中,它产生了以下内容:

$ base64 random
Tg8j3hAv/u4=

如果您想在家一起玩,可以运行生成相同的文件:

echo -n 'Tg8j3hAv/u4=' | base64 -d > random

但是,当我尝试在 Javascript 中读取该文件并将其转换为 base64 时,我得到了不同的结果:

Tg8j77+9EC/vv73vv70=

看起来有点相似,但是里面有一些其他的字符。

我是这样得到它的:

function readTextFile(file)
{
    let fileContents;
    var rawFile = new XMLHttpRequest();
    rawFile.open("GET", file, false);
    rawFile.onreadystatechange = function ()
    {
        if(rawFile.readyState === 4)
        {
            if(rawFile.status === 200 || rawFile.status == 0)
            {
                fileContents = rawFile.responseText;
            }
        }
    }
    rawFile.send(null);
    return fileContents;
}
var fileContents = readTextFile("file:///Users/henrytk/tmp/stuff/random");
console.log(btoa(unescape(encodeURIComponent(fileContents))));

// I also tried
console.log(Base64.encode(fileContents));
// from http://www.webtoolkit.info/javascript_base64.html#.YVW4WaDTW_w
// but I got the same result

这是怎么回事?这与我阅读文件的方式有关吗?我希望能够以 运行 本地 的方式同步读取该文件 - 没有 NodeJS,没有花哨的第三方库,如果可能的话。

我认为这是问题所在:

fileContents = rawFile.responseText

这会将您的文件读取为 JavaScript 字符串,并非所有二进制文件都是有效的 JavaScript 字符代码点。

我会推荐使用 fetch 来获取 blob,因为这是我最了解的方法:

async function readTextFileAsBlob(file) {

    const response = await fetch( file );

    const blob = await response.blob();

    return blob;

}

然后,使用浏览器的 FileReader 将 blob 转换为 base64。
(也许与 Linux 工具匹配?)

const blobToBase64DataURL = blob => new Promise( 
    
    resolvePromise => {

        const reader = new FileReader();
    
        reader.onload = () => resolvePromise( reader.result );
    
        reader.readAsDataURL( blob );

    }

);

在您的示例中,您将像这样使用这些函数:

readTextFileAsBlob( "file:///Users/henrytk/tmp/stuff/random" ).then(

    async blob => {

        const base64URL = await blobToBase64DataURL( blob );

        console.log( base64URL );

    }

);

这会给你一个 URL 就像 data://...。您需要拆分 URL 部分,但如果一切顺利,最后一位应该是正确的 base64 数据。 (希望如此)。