read - mostrar un archivo con javascript
Leer n lĂneas de un archivo de texto grande (2)
El archivo más pequeño que tengo tiene> 850k líneas y cada línea es de longitud desconocida. El objetivo es leer n
líneas de este archivo en el navegador. Leerlo completamente no va a suceder.
Aquí está el HTML <input type="file" name="file" id="file">
y el JS I have:
var n = 10;
var reader = new FileReader();
reader.onload = function(progressEvent) {
// Entire file
console.log(this.result);
// By lines
var lines = this.result.split(''/n'');
for (var line = 0; line < n; line++) {
console.log(lines[line]);
}
};
Obviamente, el problema aquí es que primero intenta hacer real todo el archivo y luego dividirlo por nueva línea. Entonces, sin importar n
, intentará leer todo el archivo y, finalmente, no leerá nada cuando el archivo sea grande.
¿Cómo debería hacerlo?
Nota: estoy dispuesto a eliminar toda la función y comenzar de cero, dado que podré console.log()
cada línea que leemos.
* "cada línea es de longitud desconocida" -> significa que el archivo es algo como esto:
(0, (1, 2))
(1, (4, 5, 6))
(2, (7))
(3, (8))
Editar:
El camino a seguir sería algo así como la aplicación de lector de archivos en archivos grandes , pero no veo cómo puedo modificar eso para leer n
líneas del archivo ...
Al usar Uint8Array para encadenar en Javascript también, se puede hacer desde allí:
var view = new Uint8Array(fr.result);
var string = new TextDecoder("utf-8").decode(view);
console.log("Chunk " + string);
pero puede que no lea la última línea como un todo, entonces, ¿cómo vas a determinar las líneas más adelante? Por ejemplo, aquí está lo que imprimió:
((7202), (u''11330875493'', u''2554375661''))
((1667), (u''9079074735'', u''6883914476'',
La lógica es muy similar a lo que escribí en mi respuesta a la aplicación de lector de archivos grandes , excepto que necesita realizar un seguimiento de la cantidad de líneas que ha procesado hasta el momento (y también la última línea leída hasta ahora, porque puede que no han terminado todavía). El siguiente ejemplo funciona para cualquier codificación que sea compatible con UTF-8; si necesita otra codificación, mire las opciones para el constructor TextDecoder
.
Si está seguro de que la entrada es ASCII (o cualquier otra codificación de un solo byte), también puede omitir el uso de TextDecoder
y leer directamente la entrada como texto utilizando el método readAsText
.
// This is just an example of the function below.
document.getElementById(''start'').onclick = function() {
var file = document.getElementById(''infile'').files[0];
if (!file) {
console.log(''No file selected.'');
return;
}
var maxlines = parseInt(document.getElementById(''maxlines'').value, 10);
var lineno = 1;
// readSomeLines is defined below.
readSomeLines(file, maxlines, function(line) {
console.log("Line: " + (lineno++) + line);
}, function onComplete() {
console.log(''Read all lines'');
});
};
/**
* Read up to and including |maxlines| lines from |file|.
*
* @param {Blob} file - The file to be read.
* @param {integer} maxlines - The maximum number of lines to read.
* @param {function(string)} forEachLine - Called for each line.
* @param {function(error)} onComplete - Called when the end of the file
* is reached or when |maxlines| lines have been read.
*/
function readSomeLines(file, maxlines, forEachLine, onComplete) {
var CHUNK_SIZE = 50000; // 50kb, arbitrarily chosen.
var decoder = new TextDecoder();
var offset = 0;
var linecount = 0;
var linenumber = 0;
var results = '''';
var fr = new FileReader();
fr.onload = function() {
// Use stream:true in case we cut the file
// in the middle of a multi-byte character
results += decoder.decode(fr.result, {stream: true});
var lines = results.split(''/n'');
results = lines.pop(); // In case the line did not end yet.
linecount += lines.length;
if (linecount > maxlines) {
// Read too many lines? Truncate the results.
lines.length -= linecount - maxlines;
linecount = maxlines;
}
for (var i = 0; i < lines.length; ++i) {
forEachLine(lines[i] + ''/n'');
}
offset += CHUNK_SIZE;
seek();
};
fr.onerror = function() {
onComplete(fr.error);
};
seek();
function seek() {
if (linecount === maxlines) {
// We found enough lines.
onComplete(); // Done.
return;
}
if (offset !== 0 && offset >= file.size) {
// We did not find all lines, but there are no more lines.
forEachLine(results); // This is from lines.pop(), before.
onComplete(); // Done
return;
}
var slice = file.slice(offset, offset + CHUNK_SIZE);
fr.readAsArrayBuffer(slice);
}
}
Read <input type="number" id="maxlines"> lines from
<input type="file" id="infile">.
<input type="button" id="start" value="Print lines to console">
¡Las transmisiones son la característica!
El equipo de whatwg está trabajando en el último flujo sobre secuencias escribibles + legibles y pronto estarán listos. Pero hasta entonces hay un web-stream-polyfill que puedes usar. Están trabajando en una forma de obtener un Flujo de lectura de blob también [1] . Pero también he creado una forma de obtener el blob de forma continua con: Screw-FileReader
Ayer también creé un puerto simpel de nodo-línea para trabajar con secuencias web en su lugar
Así que esto podría ser bastante simple como esto:
// Simulate a file
var csv =
`apple,1,$1.00
banana,4,$0.20
orange,3,$0.79`
var file = new Blob([csv])
var n = 0
var controller
var decoder = new TextDecoder
var stdout = new WritableStream({
start(c) {
controller = c
},
write(chunk, a) {
// Calling controller.error will also put the byLine in an errored state
// Causing the file stream to stop reading more data also
if (n == 1) controller.error("don''t need more lines")
chunk = decoder.decode(chunk)
console.log(`chunk[${n++}]: ${chunk}`)
}
})
file
.stream()
.pipeThrough(byLine())
// .pipeThrough(new TextDecoder) something like this will work eventually
.pipeTo(stdout)
<script src="https://cdn.rawgit.com/creatorrr/web-streams-polyfill/master/dist/polyfill.min.js"></script>
<script src="https://cdn.rawgit.com/jimmywarting/Screw-FileReader/master/index.js"></script>
<!-- after a year or so you only need byLine -->
<script src="https://cdn.rawgit.com/jimmywarting/web-byline/master/index.js"></script>