it-swarm.com.de

Wie lade ich eine Zip-Datei im Speicher von NodeJs herunter und entpacke sie?

Ich möchte eine Zip-Datei aus dem Internet herunterladen und im Speicher entpacken, ohne sie in einer temporären Datei zu speichern. Wie kann ich das machen?

Folgendes habe ich versucht:

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
     });
  });

[BEARBEITEN] Wie vorgeschlagen, habe ich versucht, die adm-Zip-Bibliothek zu verwenden, und ich kann dies immer noch nicht zum Laufen bringen:

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
    });
42
pathikrit

Sie benötigen eine Bibliothek, die Puffer verarbeiten kann. Die neueste Version von adm-Zip Wird besorgt:

npm install adm-Zip

Meine Lösung verwendet die http.get-Methode, da sie Buffer-Chunks zurückgibt.

Code:

var file_url = 'http://notepad-plus-plus.org/repository/7.x/7.6/npp.7.6.bin.x64.Zip';

var AdmZip = require('adm-Zip');
var http = require('http');

http.get(file_url, function(res) {
  var data = [], dataLen = 0; 

  res.on('data', function(chunk) {
    data.Push(chunk);
    dataLen += chunk.length;

  }).on('end', function() {
    var buf = Buffer.alloc(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++) {
      if (zipEntries[i].entryName.match(/readme/))
        console.log(Zip.readAsText(zipEntries[i]));
    }
  });
});

Die Idee ist, ein Array von Puffern zu erstellen und diese am Ende zu einem neuen zu verketten. Dies liegt an der Tatsache, dass die Größe von Puffern nicht geändert werden kann.

pdate

Dies ist eine einfachere Lösung, bei der das Modul request verwendet wird, um die Antwort in einem Puffer zu erhalten, indem encoding: null in den Optionen. Es folgt auch Weiterleitungen und löst http/https automatisch auf.

var file_url = 'https://github.com/mihaifm/linq/releases/download/3.1.1/linq.js-3.1.1.Zip';

var AdmZip = require('adm-Zip');
var request = require('request');

request.get({url: file_url, encoding: null}, (err, res, body) => {
  var Zip = new AdmZip(body);
  var zipEntries = Zip.getEntries();
  console.log(zipEntries.length);

  zipEntries.forEach((entry) => {
    if (entry.entryName.match(/readme/i))
      console.log(Zip.readAsText(entry));
  });
});

Das body der Antwort ist ein Puffer, der direkt an AdmZip übergeben werden kann, wodurch der gesamte Prozess vereinfacht wird.

67
mihai

Leider können Sie den Antwort-Stream nicht in den Entpack-Job leiten , da dies der Knoten zlib lib zulässt. Sie müssen und zwischenspeichern Warten Sie bis zum Ende der Antwort. Ich empfehle Ihnen, die Antwort bei großen Dateien auf einen fs -Stream zu leiten, da Sie sonst Ihren Speicherplatz blitzschnell ausfüllen!

Ich verstehe nicht ganz, was Sie versuchen, aber imho das ist der beste Ansatz . Sie sollten Ihre Daten nur so lange im Speicher behalten, wie Sie sie wirklich benötigen und dann zum csv-Parser.

Wenn Sie alle Ihre Daten im Speicher behalten möchten, können Sie die csv-Parsermethode fromPath durch from ersetzen, die stattdessen einen Puffer benötigt und in getData direkt unzipped zurückgibt.

Sie können AMDZip (wie @mihai sagte) anstelle von node-Zip Verwenden, achten Sie nur darauf, dass AMDZip noch nicht in npm veröffentlicht ist. Sie benötigen also:

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

N.B. Annahme: Die Zip-Datei enthält nur eine Datei

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)
  })
})
6
kilianc

Wenn Sie unter MacOS oder Linux arbeiten, können Sie mit dem Befehl unzip aus stdin entpacken.

In diesem Beispiel lese ich die Zip-Datei aus dem Dateisystem in ein Buffer -Objekt, aber es funktioniert auch mit einer heruntergeladenen Datei:

// 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();

Welches ist eigentlich nur die Knoten-Version von:

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

[~ # ~] edit [~ # ~] : Es ist erwähnenswert, dass dies nicht funktioniert, wenn die Eingabe-Zip zu groß ist, um in einer eingelesen zu werden Stück von stdin. Wenn Sie größere Dateien lesen müssen und Ihre Zip-Datei nur eine Datei enthält, können Sie funzip anstelle von unzip verwenden:

var unzip = spawn("funzip");

Wenn Ihre Zip-Datei mehrere Dateien enthält (und die gewünschte Datei nicht die erste ist), muss ich leider sagen, dass Sie Pech haben. Das Entpacken muss in der Datei .Zip Gesucht werden, da Zip-Dateien nur ein Container sind und das Entpacken möglicherweise nur die letzte Datei darin entpackt. In diesem Fall müssen Sie die Datei vorübergehend speichern ( Node-Temp ist praktisch).

4
enyo

Vor zwei Tagen das Modul node-Zip wurde veröffentlicht, ein Wrapper für die reine JavaScript-Version von Zip: JSZip .

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