FileReader.readAsArrayBuffer
を使用して奇妙な問題に直面しています。これはFirefoxにのみ影響するようです(現在のバージョン-v40でテストしました)。何か間違ったことをしているだけなのか、これがFirefoxのバグなのかわかりません。
readAsArrayBuffer
を使用して<input>
フィールドで指定されたファイルを読み取るJavaScriptがあります。通常の状況では、すべてが正常に機能します。ただし、ユーザーが<input>
フィールドで選択した後にファイルを変更すると、readAsArrayBuffer
が非常に混乱する可能性があります。
ArrayBuffer
から返されるreadAsArrayBuffer
の長さは、常にファイルの元の長さです。ユーザーがファイルを変更して大きくする場合、元のサイズより後のバイトは取得されません。ユーザーがファイルを小さくして変更すると、バッファーは同じサイズのままで、バッファーの「超過」には文字コード90(文字列として表示される場合は大文字の「Z」)が入力されます。
このコードは非常に単純で、テストした他のすべてのブラウザーで完全に機能するため、Firefoxの問題だと考えています。私は バグとして報告 をFirefoxに報告しましたが、これが私が間違っていることの明らかなものではないことを確認したいと思います。
この動作は、次のコードスニペットで再現できます。あなたがしなければならないのは:
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>
スニペットが機能しない場合、サンプルコードはここでJSFiddleとしても利用可能です: https://jsfiddle.net/Lv5y9m2u/
興味深いことに、Firefoxはファイルが変更されてもバッファサイズをキャッシュしているようです。
これを参照することができます link 、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();
Firefoxのバグに当たっていると思います。ただし、指摘したとおり、readAsArrayBuffer
はFirefoxを除くすべてのサポートされているブラウザーで正しく動作しますが、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);
}
}
使用法:
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);
});
作業フィドル: https://jsfiddle.net/Lv5y9m2u/6/
ブラウザサポート:
readAsBinaryString
を使用しますが、これは問題ありません。readAsArrayBuffer
を使用します。FileReader
API全体はサポートされていません。readAsBinaryString
を使用します。