Saltar al contenido

¿La forma más sencilla de descargar y descomprimir archivos en Node.js multiplataforma?

Tenemos el arreglo a esta cuestión, al menos eso deseamos. Si tienes interrogantes puedes escribirlo en el apartado de comentarios, para nosotros será un gusto ayudarte

Solución:

Es 2017 (26 de octubre, para ser exactos).

Para una tecnología antigua y omnipresente como descomprimir, esperaría que existiera una biblioteca de descompresión node.js bastante popular y madura que esté “estancada” y “sin mantenimiento” porque está “completa”.

Sin embargo, la mayoría de las bibliotecas parecen ser completamente terribles o tienen compromisos recientes como hace solo unos meses. Esto es bastante preocupante … así que revisé varias bibliotecas de descompresión, leí sus documentos y probé sus ejemplos para tratar de descubrir WTF. Por ejemplo, he probado estos:

  • eljoshwolfe/yauzl
  • Antela/node-stream-zip
  • ZJONSSON/node-unzipper
  • EvanOxfeld/node-unzip
  • Stuk/jszip
  • kriskowal/zip

Actualización 2020: aún no lo he probado, pero también hay un archivador

Recomendación superior: yauzl

Funciona muy bien para el archivo completamente descargado. No es tan bueno para la transmisión.

Bien documentada. Funciona bien. Tiene sentido.

2da elección: node-stream-zip

de antelle node-stream-zip parece ser el mejor

Instalar en pc:

npm install --save node-stream-zip

Uso:

'use strict';

var fs = require('fs');
var StreamZip = require('node-stream-zip');

var zip = new StreamZip(
  file: './example.zip'
, storeEntries: true
);

zip.on('error', function (err)  console.error('[ERROR]', err); );

zip.on('ready', function () 
  console.log('All entries read: ' + zip.entriesCount);
  //console.log(zip.entries());
);

zip.on('entry', function (entry) 
  var pathname = path.resolve('./temp', entry.name);
  if (/../.test(path.relative('./temp', pathname))) 
      console.warn("[zip warn]: ignoring maliciously crafted paths in zip file:", entry.name);
      return;
  

  if ('/' === entry.name[entry.name.length - 1]) 
    console.log('[DIR]', entry.name);
    return;
  

  console.log('[FILE]', entry.name);
  zip.stream(entry.name, function (err, stream) 
    if (err)  console.error('Error:', err.toString()); return; 

    stream.on('error', function (err)  console.log('[ERROR]', err); return; );

    // example: print contents to screen
    //stream.pipe(process.stdout);

    // example: save contents to file
    fs.mkdir(
      path.dirname(pathname),
       recursive: true ,
      function (err) 
        stream.pipe(fs.createWriteStream(pathname));
      
    );
  );
);

Advertencia de seguridad:

No estoy seguro si esto comprueba entry.name para rutas creadas con fines malintencionados que se resolverían incorrectamente (como ../../../foo o /etc/passwd).

Puede comprobarlo usted mismo fácilmente comparando /../.test(path.relative('./to/dir', path.resolve('./to/dir', entry.name))).

ventajas: (¿Por qué creo que es el mejor?)

  • puede descomprimir archivos normales (quizás no algunos locos con extensiones raras)
  • puede transmitir
  • parece no tener que cargar todo el zip para leer las entradas
  • tiene ejemplos en JavaScript normal (no compilado)
  • no incluye el fregadero de la cocina (es decir, carga de URL, S3 o capas de base de datos)
  • usa algún código existente de una biblioteca popular
  • no tiene demasiado hipster sin sentido o ninja-foo en el código

Contras:

  • Se traga los errores como un hipopótamo hambriento
  • Lanza cadenas en lugar de errores (sin rastros de pila)
  • zip.extract() no parece funcionar (por eso usé zip.stream() en mi ejemplo)

Subcampeón: node-unzipper

Instalar en pc:

npm install --save unzipper

Uso:

'use strict';

var fs = require('fs');
var unzipper = require('unzipper');

fs.createReadStream('./example.zip')
  .pipe(unzipper.Parse())
  .on('entry', function (entry) 
    var fileName = entry.path;
    var type = entry.type; // 'Directory' or 'File'

    console.log();
    if (//$/.test(fileName)) 
      console.log('[DIR]', fileName, type);
      return;
    

    console.log('[FILE]', fileName, type);

    // TODO: probably also needs the security check

    entry.pipe(process.stdout/*fs.createWriteStream('output/path')*/);
    // NOTE: To ignore use entry.autodrain() instead of entry.pipe()
  );

ventajas:

  • Parece funcionar de manera similar a node-stream-zippero menos control
  • Una horquilla más funcional de unzip
  • Parece que se ejecuta en serie en lugar de en paralelo

Contras:

  • Fregadero de la cocina mucho? Solo incluye un montón de cosas que no están relacionadas con la descompresión
  • Lee todo el archivo (por fragmentos, lo cual está bien), no solo búsquedas aleatorias

Echa un vistazo a adm-zip.

ADM-ZIP es una implementación de JavaScript puro para la compresión de datos zip para NodeJS.

La biblioteca le permite:

  • descomprimir archivos zip directamente en el disco o en los búferes en memoria
  • comprimir archivos y almacenarlos en el disco en .zip formato o en búferes comprimidos
  • actualizar el contenido de/agregar nuevos/eliminar archivos de un archivo existente .zip

Node tiene soporte incorporado para gzip y deflate a través del módulo zlib:

var zlib = require('zlib');

zlib.gunzip(gzipBuffer, function(err, result) 
    if(err) return console.error(err);

    console.log(result);
);

Editar: Usted puede incluso pipe los datos directamente a través de, por ejemplo Gunzip (usando solicitud):

var request = require('request'),
    zlib = require('zlib'),
    fs = require('fs'),
    out = fs.createWriteStream('out');

// Fetch http://example.com/foo.gz, gunzip it and store the results in 'out'
request('http://example.com/foo.gz').pipe(zlib.createGunzip()).pipe(out);

Para los archivos tar, existe el módulo tar de Isaacs, que es utilizado por npm.

Edición 2: Respuesta actualizada como zlib no apoya la zip formato. Esto solo funcionará para gzip.

Tienes la opción de añadir valor a nuestro contenido añadiendo tu veteranía en las explicaciones.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *