Javascript 在 Firefox 中对更改的文件使用 FileReader.readAsArrayBuffer()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32215538/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 07:45:28  来源:igfitidea点击:

Using FileReader.readAsArrayBuffer() on changed files in Firefox

javascriptfirefoxfilereaderfileapi

提问by Stephen McDaniel

I'm running into an odd problem using FileReader.readAsArrayBufferthat only seems to affect Firefox (I tested in the current version - v40). I can't tell if I'm just doing something wrong or if this is a Firefox bug.

我在使用时遇到了一个奇怪的问题FileReader.readAsArrayBuffer,它似乎只影响 Firefox(我在当前版本 - v40 中进行了测试)。我不知道是我做错了什么,还是 Firefox 的错误。

I have some JavaScript that uses readAsArrayBufferto read a file specified in an <input>field. Under normal circumstances, everything works correctly. However, if the user modifies the file after selecting it in the <input>field, readAsArrayBuffercan get very confused.

我有一些 JavaScriptreadAsArrayBuffer用于读取<input>字段中指定的文件。在正常情况下,一切正常。但是,如果用户在<input>字段中选择文件后对其进行修改,readAsArrayBuffer则会变得非常困惑。

The ArrayBufferI get back from readAsArrayBufferalways has the length that the file was originally. If the user changes the file to make it larger, I don't get any of the bytes after the original size. If the user changes the file to make it smaller, the buffer is still the same size and the 'excess' in the buffer is filled with character codes 90 (capital letter 'Z' if viewed as a string).

ArrayBuffer我回来的readAsArrayBuffer总是有长度的文件原本。如果用户更改文件以使其更大,则在原始大小之后我不会获得任何字节。如果用户更改文件以使其更小,缓冲区的大小仍然相同,缓冲区中的“多余”填充字符代码 90(如果将其视为字符串,则为大写字母“Z”)。

Since this code is so simple and works perfectly in every other browser I tested, I'm thinking it's a Firefox issue. I've reported it as a bugto Firefox but I want to make sure this isn't just something obvious I'm doing wrong.

由于这段代码非常简单并且在我测试过的所有其他浏览器中都能完美运行,我认为这是 Firefox 的问题。我已将其作为错误报告给 Firefox,但我想确保这不仅仅是我做错的明显问题。

The behavior can be reproduced by the following code snippet. All you have to do is:

可以通过以下代码片段重现该行为。您所要做的就是:

  1. Browse for a text file that has 10 characters in it (10 is not a magic number - I'm just using it as an example)
  2. Observe that the result is an array of 10 items representing the character codes of each item
  3. While this is still running, delete 5 characters from the file and save
  4. Observe that the result is still an array of 10 items - the first 5 are correct but the last 5 are all 90 (capital letter Z)
  5. Now added 10 characters (so the file is now 15 characters long)
  6. Observe that the result is still an array of 10 items - the last 5 are not returned
  1. 浏览一个包含 10 个字符的文本文件(10 不是一个幻数——我只是以它为例)
  2. 观察结果是一个包含 10 个条目的数组,代表每个条目的字符代码
  3. 当它仍在运行时,从文件中删除 5 个字符并保存
  4. 观察结果仍然是一个包含 10 个项目的数组 - 前 5 个是正确的,但最后 5 个都是 90(大写字母 Z)
  5. 现在添加了 10 个字符(所以文件现在是 15 个字符长)
  6. 观察结果仍然是一个包含 10 项的数组——最后 5 项没有返回

function ReadFile() {
  var input = document.getElementsByTagName("input")[0];
  var output = document.getElementsByTagName("textarea")[0];

  if (input.files.length === 0) {
    output.value = 'No file selected';
    window.setTimeout(ReadFile, 1000);
    return;
  }

  var fr = new FileReader();
  fr.onload = function() {
    var data = fr.result;
    var array = new Int8Array(data);
    output.value = JSON.stringify(array, null, '  ');
    window.setTimeout(ReadFile, 1000);
  };
  fr.readAsArrayBuffer(input.files[0]);

  //These two methods work correctly
  //fr.readAsText(input.files[0]);
  //fr.readAsBinaryString(input.files[0]);
}

ReadFile();
<input type="file" />
<br/>
<textarea cols="80" rows="10"></textarea>

In case the snippet does not work, the sample code is also available as a JSFiddle here: https://jsfiddle.net/Lv5y9m2u/

如果代码段不起作用,示例代码也可作为 JSFiddle 使用:https://jsfiddle.net/Lv5y9m2u/

采纳答案by Pavan Kumar Jorrigala

Interesting, looks like Firefox is caching the buffer size even the file is modified.

有趣的是,即使文件被修改,Firefox 似乎也在缓存缓冲区大小。

You can refer to this link, replaced readAsArrayBufferwith is custom functionality which uses readAsBinaryString. Its working fine in Firefox and Chrome

您可以参考此链接,替换readAsArrayBuffer为使用readAsBinaryString. 它在 Firefox 和 Chrome 中运行良好

function ReadFile() {
var input = document.getElementsByTagName("input")[0];
var output = document.getElementsByTagName("textarea")[0];

if (input.files.length === 0) {
    output.value = 'No file selected';
    window.setTimeout(ReadFile, 1000);
    return;
}

var fr = new FileReader();
fr.onload = function () {
    var data = fr.result;
    var array = new Int8Array(data);
    output.value = JSON.stringify(array, null, '  ');
    window.setTimeout(ReadFile, 1000);
};
fr.readAsArrayBuffer(input.files[0]);



//These two methods work correctly
//fr.readAsText(input.files[0]);
//fr.readAsBinaryString(input.files[0]);
}
if (FileReader.prototype.readAsArrayBuffer && FileReader.prototype.readAsBinaryString) {
    FileReader.prototype.readAsArrayBuffer = function readAsArrayBuffer () {
        this.readAsBinaryString.apply(this, arguments);
        this.__defineGetter__('resultString', this.__lookupGetter__('result'));
        this.__defineGetter__('result', function () {
            var string = this.resultString;
            var result = new Uint8Array(string.length);
            for (var i = 0; i < string.length; i++) {
                result[i] = string.charCodeAt(i);
            }
            return result.buffer;
        });
    };
}
ReadFile();

回答by FelisCatus

I think you are hitting a bug of Firefox. However, as you pointed out, readAsArrayBufferbehaves correctly in every supported browser except Firefox while readAsBinaryStringis supported by every browser except IE.

我认为您遇到了 Firefox 的错误。但是,正如您所指出的,readAsArrayBuffer在除 Firefox 之外的每个支持的浏览器中都可以正常运行,而readAsBinaryString在除 IE 之外的每个浏览器中都支持。

Therefore, it is possible to prefer readAsBinaryStringwhen it exists and fail back to readAsArrayBufferotherwise.

因此,有可能readAsBinaryString在它存在时进行优先选择,而在readAsArrayBuffer其他情况下故障恢复。

function readFileAsArrayBuffer(file, success, error) {
    var fr = new FileReader();
    fr.addEventListener('error', error, false);
    if (fr.readAsBinaryString) {
        fr.addEventListener('load', function () {
            var string = this.resultString != null ? this.resultString : this.result;
            var result = new Uint8Array(string.length);
            for (var i = 0; i < string.length; i++) {
                result[i] = string.charCodeAt(i);
            }
            success(result.buffer);
        }, false);
        return fr.readAsBinaryString(file);
    } else {
        fr.addEventListener('load', function () {
            success(this.result);
        }, false);
        return fr.readAsArrayBuffer(file);
    }
}

Usage:

用法:

readFileAsArrayBuffer(input.files[0], function(data) {
    var array = new Int8Array(data);
    output.value = JSON.stringify(array, null, '  ');
    window.setTimeout(ReadFile, 1000);
}, function (e) {
    console.error(e);
});

Working fiddle: https://jsfiddle.net/Lv5y9m2u/6/

工作小提琴:https: //jsfiddle.net/Lv5y9m2u/6/

Browser Support:

浏览器支持:

  • Firefox: Uses readAsBinaryString, which is not problematic.
  • IE >= 10: Uses readAsArrayBufferwhich is supported.
  • IE <= 9: The entire FileReaderAPI is not supported.
  • Almost all other browsers: Uses readAsBinaryString.
  • Firefox:使用readAsBinaryString,这没有问题。
  • IE >= 10:使用readAsArrayBuffer支持。
  • IE <= 9:FileReader不支持整个API。
  • 几乎所有其他浏览器:使用readAsBinaryString.