HTML5文件API读作文本和二进制文件

tco*_*ooc 31 html javascript html5 file

我目前正在研究HTML5文件API,我需要获取二进制文件数据. The FileReaderreadAsText,readAsDataURL方法工作正常,但readAsBinaryString返回相同的数据readAsText.

我需要二进制数据,但我得到一个文本字符串.我错过了什么吗?

T.J*_*der 73

注意:2018年:readAsBinaryString已过时.对于之前您已经使用过它的用例,这些天你会使用readAsArrayBuffer(或在某些情况下readAsDataURL).


readAsBinaryString说数据必须表示为二进制字符串,其中:

...每个字节由[0..255]范围内的整数表示.

JavaScript最初没有"二进制"类型(直到ECMAScript 5的WebGL支持Typed Array*(详情如下) - 它已被ECMAScript 2015的ArrayBuffer取代)所以他们使用了String,保证没有存储字符在String中将超出0..255的范围.(他们本可以使用数组来代替,但他们没有;也许大型字符串比大数字数组更具内存效率,因为数字是浮点数.)

如果你正在读这主要是在西部的脚本文本(主要是英语,例如)的文件,那么该字符串看起来会很多像文本.如果您读取其中包含Unicode字符的文件,您应该注意到一个区别,因为JavaScript字符串是UTF-16**(详情如下),因此某些字符的值大于255,而根据文件的"二进制字符串" API规范不会有任何高于255的值(对于Unicode代码点的两个字节,您有两个单独的"字符").

如果您正在读取一个完全不是文本的文件(可能是图像),您可能仍会在readAsText和之间得到非常相似的结果readAsBinaryString,但是readAsBinaryString知道不会有任何解释多字节序列的尝试作为人物.您不知道如果使用readAsText,因为readAsText将使用编码确定来尝试找出文件的编码是什么,然后将其映射到JavaScript的UTF-16字符串.

如果您创建文件并将其存储为ASCII或UTF-8以外的其他内容,则可以看到效果.(在Windows中,您可以通过记事本执行此操作;将"另存为"作为带有"Unicode"的编码下拉列表,通过该下拉列表查看它们似乎意味着UTF-16的数据;我确定Mac OS和*nix编辑器具有类似的功能.)这是一个页面,它以两种方式转储读取文件的结果:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Show File Data</title>
<style type='text/css'>
body {
    font-family: sans-serif;
}
</style>
<script type='text/javascript'>

    function loadFile() {
        var input, file, fr;

        if (typeof window.FileReader !== 'function') {
            bodyAppend("p", "The file API isn't supported on this browser yet.");
            return;
        }

        input = document.getElementById('fileinput');
        if (!input) {
            bodyAppend("p", "Um, couldn't find the fileinput element.");
        }
        else if (!input.files) {
            bodyAppend("p", "This browser doesn't seem to support the `files` property of file inputs.");
        }
        else if (!input.files[0]) {
            bodyAppend("p", "Please select a file before clicking 'Load'");
        }
        else {
            file = input.files[0];
            fr = new FileReader();
            fr.onload = receivedText;
            fr.readAsText(file);
        }

        function receivedText() {
            showResult(fr, "Text");

            fr = new FileReader();
            fr.onload = receivedBinary;
            fr.readAsBinaryString(file);
        }

        function receivedBinary() {
            showResult(fr, "Binary");
        }
    }

    function showResult(fr, label) {
        var markup, result, n, aByte, byteStr;

        markup = [];
        result = fr.result;
        for (n = 0; n < result.length; ++n) {
            aByte = result.charCodeAt(n);
            byteStr = aByte.toString(16);
            if (byteStr.length < 2) {
                byteStr = "0" + byteStr;
            }
            markup.push(byteStr);
        }
        bodyAppend("p", label + " (" + result.length + "):");
        bodyAppend("pre", markup.join(" "));
    }

    function bodyAppend(tagName, innerHTML) {
        var elm;

        elm = document.createElement(tagName);
        elm.innerHTML = innerHTML;
        document.body.appendChild(elm);
    }

</script>
</head>
<body>
<form action='#' onsubmit="return false;">
<input type='file' id='fileinput'>
<input type='button' id='btnLoad' value='Load' onclick='loadFile();'>
</form>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

如果我使用UTF-16中存储的"Testing 1 2 3"文件,我得到的结果如下:

Text (13):

54 65 73 74 69 6e 67 20 31 20 32 20 33

Binary (28):

ff fe 54 00 65 00 73 00 74 00 69 00 6e 00 67 00 20 00 31 00 20 00 32 00 20 00 33 00

正如你所看到的,readAsText解释了字符,所以我得到13("测试1 2 3"的长度),readAsBinaryString但没有,所以我得到28(两个字节的BOM加上每个字符的两个字节).


*XMLHttpRequest.responseresponseType = "arraybuffer"在HTML 5的支持.

**"JavaScript字符串是UTF-16"似乎是一个奇怪的陈述; 他们不只是Unicode吗?不,JavaScript字符串是一系列UTF-16代码单元 ; 你看代理对作为两个独立的JavaScript"人物",即使事实上,代理对作为一个整体是一个字符.请参阅链接了解详细信息.

  • @digitalFresh:字符串*是*二进制数据.在您发表评论时,我发布了一个可能有所帮助的示例.JavaScript没有"二进制"类型,因此它们带有一个String,保证字符串中存储的字符不在0..255范围之外.(他们本可以使用一组数字代替,但他们没有.)该示例显示了如何从字符串中获取"字符"的原始值. (2认同)