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?

¿Fue útil?

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:

  1. 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").
  2. 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.
  3. Comprobar la cabecera if-modified-since contra la fecha mtime 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).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top