J'ai un long fichier à analyser. Parce que c'est très long, j'ai besoin de le faire morceau par morceau. J'ai essayé ceci:
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 );
}
}
Après l'avoir lancé, je ne vois que le premier morceau dans la console. Si je modifie 'console.log' en jquery, je ne vois que le premier bloc dans cette div. Qu'en est-il des autres morceaux? Comment le faire fonctionner?
FileReader API est asynchrone, vous devez donc le gérer avec des appels block
. Un for loop
ne ferait pas l'affaire, car il n'attendrait pas que chaque lecture soit terminée avant de lire le morceau suivant .
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's start the read with the first block
chunkReaderBlock(offset, chunkSize, file);
}
Le deuxième argument de slice
est en fait l'octet de fin. Votre code devrait ressembler à quelque chose comme:
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);
}
}
Ou vous pouvez utiliser cette BlobReader
pour une interface plus simple:
BlobReader(blob)
.readText(function (text) {
console.log('The text in the blob is', text);
});
Plus d'information:
Répondez @ alediaferia à une classe ( Version TypeScript here ) et retournez le résultat dans une promesse. De braves codeurs l'auraient même intégré dans un itérateur asynchrone ...
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;
}
}
Exemple d'impression d'un fichier entier dans la console (dans un contexte async context)
const fileStreamer = new FileStreamer(aFile);
while (!fileStreamer.isEndOfFile()) {
const data = await fileStreamer.readBlockAsText();
console.log(data);
}
Vous pouvez profiter de Response (une partie de fetch ) pour convertir la plupart des choses en n'importe quoi d'autre blob, text, json et obtenir également un ReadableStream qui peut vous aider à lire le blob en morceaux ????
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')
})
Old answer (WritableStreams pipeTo et pipeThrough n'étaient pas implémentés auparavant)
Je suis arrivé avec une idéa intéressante qui est probablement très rapide, car elle convertira le blob en ReadableByteStreamReader probablement beaucoup plus facile aussi, car vous n'avez pas besoin de gérer des éléments tels que la taille du bloc et le décalage, puis de tout faire de manière récursive
function streamBlob(blob) {
const reader = new Response(blob).body.getReader()
const pump = reader => reader.read()
.then(({ value, done }) => {
if (done) return
// uint8array chunk (use TextDecoder to read as text)
console.log(value)
return pump(reader)
})
return pump(reader)
}
streamBlob(new Blob(['bloby'])).then(() => {
console.log('done')
})
Analyser le fichier volumineux en petit morceau en utilisant la méthode simple:
//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++;
}
};