¿Cuáles son los pros y los contras de fs.createReadStream vs fs.readFile en Node.js?
-
15-10-2019 - |
Pregunta
Estoy curioseaba con Node.js y he descubierto dos maneras de leer un archivo y enviarlo por el cable, una vez que haya establecido que no existe y he enviado el tipo MIME adecuado con writeHead:
// read the entire file into memory and then spit it out
fs.readFile(filename, function(err, data){
if (err) throw err;
response.write(data, 'utf8');
response.end();
});
// read and pass the file as a stream of chunks
fs.createReadStream(filename, {
'flags': 'r',
'encoding': 'binary',
'mode': 0666,
'bufferSize': 4 * 1024
}).addListener( "data", function(chunk) {
response.write(chunk, 'binary');
}).addListener( "close",function() {
response.end();
});
Estoy en lo cierto al suponer que fs.createReadStream podría proporcionar una mejor experiencia de usuario si el archivo en cuestión era algo grande, como un video? Se siente como que podría ser menor bloque-ish; ¿Es esto cierto? ¿Hay otras ventajas, desventajas, advertencias, o trampas que necesito saber?
Solución
Un mejor enfoque, si sólo se va a conectar "datos" a "escritura ()" y "cerca" de "fin ()":
// 0.3.x style
fs.createReadStream(filename, {
'bufferSize': 4 * 1024
}).pipe(response)
// 0.2.x style
sys.pump(fs.createReadStream(filename, {
'bufferSize': 4 * 1024
}), response)
El enfoque read.pipe(write)
o sys.pump(read, write)
tiene el beneficio de añadir también el control de flujo. Por lo tanto, si el flujo de escritura no puede aceptar datos tan rápidamente, que va a contar la secuencia de lectura a retroceder, a fin de minimizar la cantidad de datos a almacenar en la memoria conseguir.
El flags:"r"
y mode:0666
están implícitos en el hecho de que se trata de un FileReadStream
. La codificación binary
está en desuso -. Si no se especifica una codificación, sólo va a trabajar con los buffers de datos en bruto
Además, se podría añadir algunas otras cosas que harán que su servicio de archivos un impermeable mucho:
- Huela para
req.headers.range
y ver si coincide con una cadena como/bytes=([0-9]+)-([0-9]+)/
. Si es así, que desea transmitir sólo de que el principio hasta el lugar final. (Missing medios número 0 ó "final"). - Hash el nodo-i y la creación de tiempo desde la llamada stat () en una cabecera ETag. Si se obtiene un encabezado de la solicitud con el "si-no-match" que coincide con la cabecera, enviar de vuelta un
304 Not Modified
. - Comprobar la cabecera
if-modified-since
contra la fechamtime
en el objeto de estadísticas. 304 si no se ha modificado desde la fecha fijada.
Además, en general, si se puede, envía una cabecera Content-Length
. (Eres stat
-ing el archivo, por lo que debe tener esto.)
Otros consejos
fs.readFile
cargará el archivo en la memoria como usted ha señalado, al tiempo que fs.createReadStream
leerá el archivo en trozos del tamaño que se especifique.
El cliente también empezará a recibir los datos más rápido usando fs.createReadStream
ya que se envía a cabo en trozos, ya que se está leyendo, mientras que fs.readFile
leerá el archivo completo y sólo entonces comenzar a enviar al cliente. Esto podría ser insignificante, pero puede hacer una diferencia si el archivo es muy grande y los discos son lentos.
Piense en esto, sin embargo, si ejecuta estas dos funciones en un archivo de 100 MB, el primero utilizará 100 MB de memoria para cargar el archivo mientras que el segundo sólo usaría como máximo de 4 KB.
Editar:. Realmente no veo ninguna razón por la que tendría que utilizar fs.readFile
sobre todo porque usted ha dicho que será la apertura de archivos de gran tamaño
Si se trata de un archivo grande entonces "readFile" podría acaparar la memoria búfer, ya que todo el contenido del archivo en la memoria y se puede bloquear el sistema. Mientras ReadStream leer en trozos.
Ejecutar este código y observar el uso de memoria en la ficha rendimiento del administrador de tareas.
var fs = require('fs');
const file = fs.createWriteStream('./big_file');
for(let i=0; i<= 1000000000; i++) {
file.write('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n');
}
file.end();
//..............
fs.readFile('./big_file', (err, data) => {
if (err) throw err;
console.log("done !!");
});
De hecho, no verá "hecho !!" mensaje. "ReadFile" no sería capaz de leer el contenido del archivo como tampón no es lo suficientemente grande como para contener el contenido del archivo.
Ahora, en lugar de "readFile", el uso ReadStream y uso de la memoria del monitor.
Nota: El código se toma de Samer buna Nodo curso sobre Pluralsight
Otra, quizás no tan bien cosa conocida, es que yo creo que es mejor nodo en la limpieza de la memoria no utilizada después de usar fs.readFile
comparación con fs.createReadStream
. Debe probar esto a verificar lo que funciona mejor. Además, sé que por cada nueva versión de nodo, esto ha hecho más que mejorar (es decir, el recolector de basura se ha convertido en más elegante con este tipo de situaciones).