web-dev-qa-db-ja.com

テキストおよびバイナリとして読み取られるHTML5 File API

現在、HTML5 File APIに取り組んでおり、バイナリファイルデータを取得する必要があります。 The FileReaderreadAsTextおよびreadAsDataURLメソッドは正常に機能しますが、readAsBinaryStringreadAsTextと同じデータを返します。

バイナリデータが必要ですが、テキスト文字列を取得しています。何か不足していますか?

31
tcooc

2018年の注readAsBinaryStringは古くなっています。以前使用していたユースケースでは、最近では readAsArrayBuffer (または場合によっては readAsDataURL を使用していました。 )代わりに。


readAsBinaryStringは、データを バイナリ文字列 で表す必要があることを示します。ここで、

...すべてのバイトは、範囲[0..255]の整数で表されます。

JavaScriptには元々「バイナリ」タイプがありませんでした(ECMAScript 5の Typed Array *(以下の詳細)のWebGLサポートまで-それは置き換えられました) ECMAScript 2015の ArrayBuffer )で、文字列に格納されている文字が0..255の範囲外にないことを保証して文字列を使用しました。 (代わりにNumbersの配列を使用することもできましたが、使用しませんでした。Numbersは浮動小数点数であるため、大きなStringsはNumbersの大きな配列よりもメモリ効率が高い可能性があります。)

ほとんどが欧文のテキスト(たとえば、ほとんどが英語)のファイルを読んでいる場合、その文字列はテキストのようなlotに見えます。 JavaScript文字列は TF-16 **(以下の詳細)とそのため、一部の文字は255を超える値を持ちますが、File API仕様による「バイナリ文字列」は255を超える値を持ちません(Unicodeコードポイントの2バイトに対して2つの個別の「文字」があります)。

テキストではないファイル(おそらく画像)を読んでいる場合、おそらくreadAsTextreadAsBinaryStringの間で非常によく似た結果が得られますが、readAsBinaryString youknowは、マルチバイトシーケンスを文字として解釈しようとする試みがないことを知っています。 readAsTextを使用する場合、readAsTextエンコードの決定 を使用してファイルのエンコードが何であるかを把握し、それをマッピングするため、 JavaScriptのUTF-16文字列。

ファイルを作成して、ASCIIまたはUTF-8以外の場所に保存すると、効果を確認できます。Windowsでは、メモ帳を使用してこれを行うことができます。 「Unicode」がドロップダウンされ、データを見るとUTF-16を意味しているように見えます。MacOSと* 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>

UTF-16で保存された「Testing 1 2 3」ファイルでそれを使用すると、次のような結果が得られます。

テキスト(13):
 
 54 65 73 74 69 6e 67 20 31 20 32 20 33 
 
バイナリ(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(「Testing 1 2 3」の長さ)を取得し、readAsBinaryStringはそうではなかったため、28(2 -byte [〜#〜] bom [〜#〜] プラス各文字に2バイト)。


* XMLHttpRequest.response with responseType = "arraybuffer"はHTML 5でサポートされています。

** "JavaScript文字列はUTF-16です"は奇妙なステートメントのように見えるかもしれません。それらは単なるユニコードではありませんか?いいえ、JavaScript文字列は 一連のUTF-16コード単位 ;です。実際には、サロゲートペア全体は1文字だけですが、サロゲートペアは2つの個別のJavaScript「文字」として表示されます。詳細については、リンクを参照してください。

72
T.J. Crowder