Javascript FileReader - анализ длинного файла в кусках
У меня есть длинный файл, который мне нужно проанализировать. Потому что очень долго мне нужно сделать это куском куска. Я пробовал это:
function parseFile(file){
var chunkSize = 2000;
var fileSize = (file.size - 1);
var foo = function(e){
console.log(e.target.result);
};
for(var i =0; i < fileSize; i += chunkSize)
{
(function( fil, start ) {
var reader = new FileReader();
var blob = fil.slice(start, chunkSize + 1);
reader.onload = foo;
reader.readAsText(blob);
})( file, i );
}
}
После запуска я вижу только первый фрагмент в консоли. Если я изменил "console.log" на jquery append на некоторый div, я вижу только первый фрагмент в этом div. А как насчет других кусков? Как заставить его работать?
Ответы
Ответ 1
FileReader API является асинхронным, поэтому вы должны обрабатывать его с помощью вызовов block
. A for loop
не будет делать трюк, так как он не дождался завершения каждого чтения перед чтением следующего фрагмента.
Здесь рабочий подход.
function parseFile(file, callback) {
var fileSize = file.size;
var chunkSize = 64 * 1024; // bytes
var offset = 0;
var self = this; // we need a reference to the current object
var chunkReaderBlock = null;
var readEventHandler = function(evt) {
if (evt.target.error == null) {
offset += evt.target.result.length;
callback(evt.target.result); // callback for handling read chunk
} else {
console.log("Read error: " + evt.target.error);
return;
}
if (offset >= fileSize) {
console.log("Done reading file");
return;
}
// of to the next chunk
chunkReaderBlock(offset, chunkSize, file);
}
chunkReaderBlock = function(_offset, length, _file) {
var r = new FileReader();
var blob = _file.slice(_offset, length + _offset);
r.onload = readEventHandler;
r.readAsText(blob);
}
// now let start the read with the first block
chunkReaderBlock(offset, chunkSize, file);
}
Ответ 2
Второй аргумент slice
на самом деле является конечным байтом. Ваш код должен выглядеть примерно так:
function parseFile(file){
var chunkSize = 2000;
var fileSize = (file.size - 1);
var foo = function(e){
console.log(e.target.result);
};
for(var i =0; i < fileSize; i += chunkSize) {
(function( fil, start ) {
var reader = new FileReader();
var blob = fil.slice(start, chunkSize + start);
reader.onload = foo;
reader.readAsText(blob);
})(file, i);
}
}
Или вы можете использовать этот BlobReader
для упрощения интерфейса:
BlobReader(blob)
.readText(function (text) {
console.log('The text in the blob is', text);
});
Дополнительная информация:
Ответ 3
Обновленный ответ @alediaferia в классе (= this.getFileSize();
}
public readBlockAsText(length: number = this.defaultChunkSize) {
const fileReader: FileReader = new FileReader();
const blob: Blob = this.file.slice(this.offset, this.offset + length);
return new Promise((resolve, reject) => {
fileReader.onloadend = (event: ProgressEvent) => {
const target: FileReader = (event.target) as FileReader;
if (target.error == null) {
const result: string = target.result;
this.offset += result.length;
this.testEndOfFile();
resolve(result);
} else {
reject(target.error);
}
};
fileReader.readAsText(blob);
});
}
private testEndOfFile(): void {
if (this.isEndOfFile()) {
console.log('Done reading file');
}
}
private getFileSize(): number {
return this.file.size;
}
} rel="nofollow noreferrer">версия для машинописи здесь) и возвращение результата в обещании. Отважные кодеры даже обернули бы его в асинхронный итератор...
class FileStreamer {
constructor(file) {
this.file = file;
this.offset = 0;
this.defaultChunkSize = 64 * 1024; // bytes
this.rewind();
}
rewind() {
this.offset = 0;
}
isEndOfFile() {
return this.offset >= this.getFileSize();
}
readBlockAsText(length = this.defaultChunkSize) {
const fileReader = new FileReader();
const blob = this.file.slice(this.offset, this.offset + length);
return new Promise((resolve, reject) => {
fileReader.onloadend = (event) => {
const target = (event.target);
if (target.error == null) {
const result = target.result;
this.offset += result.length;
this.testEndOfFile();
resolve(result);
}
else {
reject(target.error);
}
};
fileReader.readAsText(blob);
});
}
testEndOfFile() {
if (this.isEndOfFile()) {
console.log('Done reading file');
}
}
getFileSize() {
return this.file.size;
}
}
Пример печати всего файла в консоли (в асинхронном контексте)
const fileStreamer = new FileStreamer(aFile);
while (!fileStreamer.isEndOfFile()) {
const data = await fileStreamer.readBlockAsText();
console.log(data);
}
Ответ 4
Вы можете воспользоваться функцией Response (частью извлечения), чтобы преобразовать большинство вещей во что-либо еще blob, text, json, а также получить ReadableStream, который может помочь вам прочитать большой двоичный объект 👍
var dest = new WritableStream({
write (str) {
console.log(str)
}
})
new Response(new Blob(['bloby']))
.body
// Decode the binary-encoded response to string
.pipeThrough(new TextDecoderStream())
.pipeTo(dest)
.then(() => {
console.log('done')
})
Ответ 5
Разбор большого файла в маленький кусок с помощью простого метода:
//Parse large file in to small chunks
var parseFile = function (file) {
var chunkSize = 1024 * 1024 * 16; //16MB Chunk size
var fileSize = file.size;
var currentChunk = 1;
var totalChunks = Math.ceil((fileSize/chunkSize), chunkSize);
while (currentChunk <= scope.totalChunks) {
var offset = (currentChunk-1) * chunkSize;
var currentFilePart = file.slice(offset, (offset+chunkSize));
console.log('Current chunk number is ', currentChunk);
console.log('Current chunk data', currentFilePart);
currentChunk++;
}
};