tutorial principiantes para node libro desde cero javascript node.js zip zlib unzip

javascript - principiantes - ¿Cómo descargar y descomprimir un archivo zip en la memoria en NodeJs?



node js download file (5)

Hace dos días se lanzó el módulo node-zip , que es un contenedor para la versión JavaScript de Zip: JSZip .

var NodeZip = require(''node-zip'') , zip = new NodeZip(zipBuffer.toString("base64"), { base64: true }) , unzipped = zip.files["your-text-file.txt"].data;

Quiero descargar un archivo comprimido de Internet y descomprimirlo en la memoria sin guardarlo en un archivo temporal. ¿Cómo puedo hacer esto?

Esto es lo que intenté:

var url = ''http://bdn-ak.bloomberg.com/precanned/Comdty_Calendar_Spread_Option_20120428.txt.zip''; var request = require(''request''), fs = require(''fs''), zlib = require(''zlib''); request.get(url, function(err, res, file) { if(err) throw err; zlib.unzip(file, function(err, txt) { if(err) throw err; console.log(txt.toString()); //outputs nothing }); });

[EDIT] Como sugerí, intenté usar la biblioteca adm-zip y todavía no puedo hacer que esto funcione:

var ZipEntry = require(''adm-zip/zipEntry''); request.get(url, function(err, res, zipFile) { if(err) throw err; var zip = new ZipEntry(); zip.setCompressedData(new Buffer(zipFile.toString(''utf-8''))); var text = zip.getData(); console.log(text.toString()); // fails });


Lamentablemente, no puede canalizar la secuencia de respuesta en el trabajo de descompresión, ya que el nodo zlib lib le permite hacerlo, debe almacenar en caché y esperar al final de la respuesta. Te sugiero que canalices la respuesta a una secuencia fs en el caso de archivos grandes, de lo contrario llenarás por completo tu memoria en un abrir y cerrar de ojos.

No entiendo completamente lo que intentas hacer, pero este es el mejor enfoque . Debería mantener sus datos en la memoria solo el tiempo que realmente los necesita , y luego transmitirlos al analizador csv .

Si desea mantener todos sus datos en la memoria, puede reemplazar el método del analizador csv de la fromPath con from que toma un búfer en su lugar y en getData return directamente unzipped

Puede usar AMDZip (como dijo @mihai) en lugar de node-zip , solo preste atención porque AMDZip aún no se ha publicado en npm, por lo que necesita:

$ npm install git://github.com/cthackers/adm-zip.git

NB Supuesto: el archivo zip contiene solo un archivo

var request = require(''request''), fs = require(''fs''), csv = require(''csv'') NodeZip = require(''node-zip'') function getData(tmpFolder, url, callback) { var tempZipFilePath = tmpFolder + new Date().getTime() + Math.random() var tempZipFileStream = fs.createWriteStream(tempZipFilePath) request.get({ url: url, encoding: null }).on(''end'', function() { fs.readFile(tempZipFilePath, ''base64'', function (err, zipContent) { var zip = new NodeZip(zipContent, { base64: true }) Object.keys(zip.files).forEach(function (filename) { var tempFilePath = tmpFolder + new Date().getTime() + Math.random() var unzipped = zip.files[filename].data fs.writeFile(tempFilePath, unzipped, function (err) { callback(err, tempFilePath) }) }) }) }).pipe(tempZipFileStream) } getData(''/tmp/'', ''http://bdn-ak.bloomberg.com/precanned/Comdty_Calendar_Spread_Option_20120428.txt.zip'', function (err, path) { if (err) { return console.error(''error: %s'' + err.message) } var metadata = [] csv().fromPath(path, { delimiter: ''|'', columns: true }).transform(function (data){ // do things with your data if (data.NAME[0] === ''#'') { metadata.push(data.NAME) } else { return data } }).on(''data'', function (data, index) { console.log(''#%d %s'', index, JSON.stringify(data, null, '' '')) }).on(''end'',function (count) { console.log(''Metadata: %s'', JSON.stringify(metadata, null, '' '')) console.log(''Number of lines: %d'', count) }).on(''error'', function (error) { console.error(''csv parsing error: %s'', error.message) }) })


Si está en MacOS o Linux, puede usar el comando descomprimir para descomprimir de stdin .

En este ejemplo, estoy leyendo el archivo zip del sistema de archivos en un objeto Buffer pero también funciona con un archivo descargado:

// Get a Buffer with the zip content var fs = require("fs") , zip = fs.readFileSync(__dirname + "/test.zip"); // Now the actual unzipping: var spawn = require(''child_process'').spawn , fileToExtract = "test.js" // -p tells unzip to extract to stdout , unzip = spawn("unzip", ["-p", "/dev/stdin", fileToExtract ]) ; // Write the Buffer to stdin unzip.stdin.write(zip); // Handle errors unzip.stderr.on(''data'', function (data) { console.log("There has been an error: ", data.toString("utf-8")); }); // Handle the unzipped stdout unzip.stdout.on(''data'', function (data) { console.log("Unzipped file: ", data.toString("utf-8")); }); unzip.stdin.end();

Que en realidad es solo la versión del nodo de:

cat test.zip | unzip -p /dev/stdin test.js

EDITAR : Vale la pena señalar que esto no funcionará si el archivo zip de entrada es demasiado grande para ser leído en un fragmento de stdin. Si necesita leer archivos más grandes, y su archivo zip contiene solo un archivo, puede usar funzip lugar de unzip :

var unzip = spawn("funzip");

Si su archivo comprimido contiene varios archivos (y el archivo que desea no es el primero) me temo que no tiene suerte. Descomprimir debe buscar en el archivo .zip ya que los archivos zip son solo un contenedor, y descomprimir solo puede descomprimir el último archivo en él. En ese caso, debe guardar el archivo temporalmente ( node-temp es útil).


var fs = require (''fs); var unzip = require (''descomprimir'');

// descomprimir a.zip en el diccionario actual

fs.createReadStream (''./ path / a.zip''). pipe (descomprimir.Extract ({ruta: ''./path/''}));

Usé el módulo de descompresión, y funcionó.


  • Necesita una biblioteca que pueda manejar búferes. La última versión de adm-zip hará:

    npm install git://github.com/cthackers/adm-zip.git

  • Mi solución usa el método http.get , ya que devuelve fragmentos de Buffer.

Código:

var file_url = ''http://bdn-ak.bloomberg.com/precanned/Comdty_Calendar_Spread_Option_20120428.txt.zip''; var request = require(''request''); var fs = require(''fs''); var AdmZip = require(''adm-zip''); var http = require(''http''); var url = require(''url''); var options = { host: url.parse(file_url).host, port: 80, path: url.parse(file_url).pathname }; http.get(options, function(res) { var data = [], dataLen = 0; res.on(''data'', function(chunk) { data.push(chunk); dataLen += chunk.length; }).on(''end'', function() { var buf = new Buffer(dataLen); for (var i=0, len = data.length, pos = 0; i < len; i++) { data[i].copy(buf, pos); pos += data[i].length; } var zip = new AdmZip(buf); var zipEntries = zip.getEntries(); console.log(zipEntries.length) for (var i = 0; i < zipEntries.length; i++) console.log(zip.readAsText(zipEntries[i])); }); });

La idea es crear una matriz de búferes y concatenarlos en uno nuevo al final. Esto se debe al hecho de que los buffers no pueden redimensionarse.