Использование FileReader.readAsArrayBuffer() для измененных файлов в Firefox
Я сталкиваюсь с странной проблемой, используя FileReader.readAsArrayBuffer
это только влияет на Firefox (я тестировал в текущей версии - v40). Я не могу сказать, делаю ли я что-то неправильно или это ошибка в Firefox.
У меня есть JavaScript, который используетreadAsArrayBuffer
читать файл, указанный в<input>
поле. В нормальных условиях все работает правильно. Однако, если пользователь изменяет файл после его выбора в <input>
поле, readAsArrayBuffer
может быть очень запутанным.
ArrayBuffer
Я вернусь изreadAsArrayBuffer
всегда имеет длину, в которой файл был изначально. Если пользователь изменяет файл, чтобы увеличить его, я не получаю ни одного байта после исходного размера. Если пользователь изменяет файл, чтобы он стал меньше, размер буфера остается прежним, а "избыток" в буфере заполняется кодами символов 90 (заглавная буква "Z", если рассматривать ее как строку).
Поскольку этот код очень прост и отлично работает в любом другом браузере, который я тестировал, я думаю, что это проблема Firefox. Я сообщил об этом как об ошибке в Firefox, но я хочу убедиться, что это не просто что-то очевидное, я делаю неправильно.
Поведение может быть воспроизведено с помощью следующего фрагмента кода. Все, что вам нужно сделать, это:
- Найдите текстовый файл, содержащий 10 символов (10 не волшебное число - я просто использую его в качестве примера)
- Обратите внимание, что в результате получается массив из 10 элементов, представляющих коды символов каждого элемента.
- Пока он еще работает, удалите 5 символов из файла и сохраните
- Обратите внимание, что результат по-прежнему массив из 10 элементов - первые 5 верны, но последние 5 все 90 (заглавная буква Z)
- Теперь добавлено 10 символов (поэтому файл теперь имеет длину 15 символов)
- Обратите внимание, что результат по-прежнему массив из 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>
Если фрагмент не работает, пример кода также доступен в виде JSFiddle здесь: https://jsfiddle.net/Lv5y9m2u/
2 ответа
Интересно, что FF кеширует размер буфера, даже если файл изменен.
Вы можете обратиться к этой ссылке, заменив readAsArrayBuffer на пользовательский функционал, который использует readAsBinaryString. работает нормально в FF и 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/
Поддержка браузера:
- Firefox: использует
readAsBinaryString
, что не является проблематичным. - IE> = 10: использует
readAsArrayBuffer
который поддерживается. - IE <= 9: весь
FileReader
API не поддерживается. - Почти все другие браузеры: использует
readAsBinaryString
,