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

Ste*_*iel 18 javascript firefox filereader fileapi

我遇到了一个奇怪的问题FileReader.readAsArrayBuffer,这似乎只影响Firefox(我在当前版本中测试过 - v40).我不知道我是做错了还是这是一个Firefox bug.

我有一些JavaScript readAsArrayBuffer用于读取<input>字段中指定的文件.在正常情况下,一切正常.但是,如果用户在<input>字段中选择后修改文件,readAsArrayBuffer可能会非常困惑.

ArrayBuffer我从后面readAsArrayBuffer总是有该文件最初的长度.如果用户更改文件以使其更大,我不会获得原始大小后的任何字节.如果用户更改文件以使其变小,则缓冲区仍然具有相同的大小,并且缓冲区中的"多余"填充有字符代码90(如果被视为字符串则为大写字母'Z').

由于此代码非常简单,并且在我测试的其他所有浏览器中都能完美运行,因此我认为这是一个Firefox问题.我已经将它报告为 Firefox的一个错误,但我想确保这不仅仅是我做错了.

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

  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();
Run Code Online (Sandbox Code Playgroud)
<input type="file" />
<br/>
<textarea cols="80" rows="10"></textarea>
Run Code Online (Sandbox Code Playgroud)

如果代码片段不起作用,示例代码也可以在这里作为JSFiddle:https://jsfiddle.net/Lv5y9m2u/

Pav*_*ala 11

有趣的是,看起来Firefox即使文件被修改也会缓存缓冲区大小.

您可以参考此链接,替换为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();
Run Code Online (Sandbox Code Playgroud)

  • 我已经更新了这个答案,包括检查`readAsBinaryString`是否存在.这让这段代码可以在IE中运行.它现在可以满足我所需要的一切 - 它可以在我需要的所有浏览器中运行,并且可以轻松地放入我现有的代码库而无需更改任何内容.如果/当Firefox错误得到修复,将来也很容易删除. (2认同)

Fel*_*tus 6

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

因此,有可能优选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);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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);
});
Run Code Online (Sandbox Code Playgroud)

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

浏览器支持:

  • Firefox:使用readAsBinaryString,这没有问题.
  • IE> = 10:使用readAsArrayBuffer支持的.
  • IE <= 9:FileReader不支持整个API.
  • 几乎所有其他浏览器:使用readAsBinaryString.