web-dev-qa-db-ja.com

Node.jsクロスプラットフォームでファイルをダウンロードおよび解凍する最も簡単な方法は?

ダウンロードと解凍の簡単な解決策を探している.Zip または .tar.gz任意のオペレーティングシステム上のNode.jsのファイル。

これが組み込まれているのか、別のライブラリを使用する必要があるのか​​はわかりません。何か案は?ほんの2、3行のコードを探しているので、次のZipファイルが来て、ノードにダウンロードしたい場合、それは簡単です。これは簡単で、組み込みである必要がありますが、何も見つかりません。ありがとう!

49
Lance Pollard

チェックアウト adm-Zip

ADM-Zipは、NodeJSのZipデータ圧縮用の純粋なJavaScript実装です。

ライブラリでは次のことができます。

  • zipファイルをディスクまたはメモリ内バッファに直接解凍します
  • ファイルを圧縮し、.Zip形式または圧縮バッファでディスクに保存します
  • 既存の.Zipのコンテンツの更新/新しいファイルの追加/削除
29
bryanmac

2017年です(正確には10月26日)。

Unzipなどの古くから普及している技術の場合、「完全」であるため「停滞」および「維持されない」かなり人気のある成熟したnode.js unzipライブラリが存在することを期待します。

しかし、ほとんどのライブラリは完全にひどいものであるか、ほんの数か月前に最近コミットされたようです。これは非常に懸念事項です...なので、いくつかの解凍ライブラリを調べ、ドキュメントを読んで、WTFを理解するために例を試しました。たとえば、私はこれらを試しました:

推奨事項:yauzl

完全にダウンロードされたファイルに最適です。ストリーミングにはあまり適していません。

よく文書化されています。うまくいく。理にかなっています。

2番目のピック:_node-stream-Zip_

antelleの _node-stream-Zip_ が最高のようです

インストール:

_npm install --save node-stream-Zip
_

使用法:

_'use strict';

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
    mkdirp(path.dirname(pathname, function (err) {
      stream.pipe(fs.createWriteStream(pathname));
    });
  });
});
_

セキュリティ警告

誤って解決される悪意を持って作成されたパス(_entry.name_や_../../../foo_など)を_/etc/passwd_でチェックするかどうかはわかりません。

/\.\./.test(path.relative('./to/dir', path.resolve('./to/dir', entry.name)))を比較することで、自分で簡単に確認できます。

長所:(なぜ最高だと思いますか?)

  • 通常のファイルを解凍できます(奇妙な拡張子を持つクレイジーなファイルではないかもしれません)
  • ストリーミングできます
  • エントリを読み込むためにZip全体をロードする必要はないようです
  • 通常のJavaScriptの例があります(コンパイルされていません)
  • キッチンシンクは含まれません(URLの読み込み、S3、またはdbレイヤー)
  • 人気のあるライブラリの既存のコードを使用します
  • コードに無意味なヒップスターやninja-fooが多すぎない

短所

  • 空腹のカバのようなエラーを飲み込む
  • エラーの代わりに文字列をスローします(スタックトレースなし)
  • Zip.extract()は機能しないようです(したがって、この例ではZip.stream()を使用しました)

次点:node-unzipper

インストール:

_npm install --save unzipper
_

使用法:

_'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()
  });
_

長所

  • _node-stream-Zip_と同様の方法で動作するようですが、制御が少ない
  • unzipのより機能的なフォーク
  • パラレルではなくシリアルで実行するようです

短所

  • キッチンはたくさんシンク?解凍に関係のないものが大量に含まれています
  • ランダムシークだけでなく、ファイル全体を(チャンク単位で)読み込みます
52
CoolAJ86

Nodeにはgzipの組み込みサポートがあり、 zlibモジュール を使用して収縮します:

var zlib = require('zlib');

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

    console.log(result);
});

編集:pipeでさえも直接データを介してGunziprequest を使用):

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

Tarアーカイブには、Isaacsの tarモジュール があり、npmで使用されます。

編集2:zlibZip形式をサポートしないため、回答を更新しました。これはgzipでのみ機能します。

yauzl は、解凍用の堅牢なライブラリです。設計原則:

  • 仕様に従ってください。ローカルファイルヘッダーをスキャンしないでください。ファイルメタデータの中央ディレクトリを読み取ります。
  • JavaScriptスレッドをブロックしないでください。非同期APIを使用および提供します。
  • メモリ使用量を制御します。 RAMで一度にファイル全体をバッファリングしないでください。
  • クラッシュしない(適切に使用した場合)。不正な形式のZipファイルがエラーをキャッチしようとしているクライアントアプリケーションを停止させないようにしてください。
  • 安全でないファイル名エントリをキャッチします。 Zipファイルエントリは、ファイル名が「/」または/ [A-Za-z]://で始まる場合、または「..」パスセグメントまたは「\」(仕様ごと)を含む場合、エラーをスローします。

現在、テスト範囲は97%です。

13
andrewrk

私はadm-Zipやunzipなどのnodejs unzipライブラリをいくつか試した後、yauzlのラッパーであるextract-Zipに決めました。実装が最も簡単なようです。

https://www.npmjs.com/package/extract-Zip

var extract = require('extract-Zip')
extract(zipfile, { dir: outputPath }, function (err) {
   // handle err
})
11
Simon Hutchison

私はこれを長い間楽しみにしていましたが、簡単な作業例は見つかりませんでしたが、これらの回答に基づいてdownloadAndUnzip()関数を作成しました。

使い方はとても簡単です:

downloadAndUnzip('http://your-domain.com/archive.Zip', 'yourfile.xml')
    .then(function (data) {
        console.log(data); // unzipped content of yourfile.xml in root of archive.Zip
    })
    .catch(function (err) {
        console.error(err);
    });

そして、ここに宣言があります:

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

var downloadAndUnzip = function (url, fileName) {

    /**
     * Download a file
     * 
     * @param url
     */
    var download = function (url) {
        return new Promise(function (resolve, reject) {
            request({
                url: url,
                method: 'GET',
                encoding: null
            }, function (err, response, body) {
                if (err) {
                    return reject(err);
                }
                resolve(body);
            });
        });
    };

    /**
     * Unzip a Buffer
     * 
     * @param buffer
     * @returns {Promise}
     */
    var unzip = function (buffer) {
        return new Promise(function (resolve, reject) {

            var resolved = false;

            var Zip = new AdmZip(buffer);
            var zipEntries = Zip.getEntries(); // an array of ZipEntry records

            zipEntries.forEach(function (zipEntry) {
                if (zipEntry.entryName == fileName) {
                    resolved = true;
                    resolve(zipEntry.getData().toString('utf8'));
                }
            });

            if (!resolved) {
                reject(new Error('No file found in archive: ' + fileName));
            }
        });
    };


    return download(url)
        .then(unzip);
};
3
Adam

.Zipで動作する次のもので成功しました。
(投稿用にここで簡略化:エラーチェックなし&すべてのファイルを現在のフォルダーに解凍します)

function DownloadAndUnzip(URL){
    var unzip = require('unzip');
    var http = require('http');
    var request = http.get(URL, function(response) {
        response.pipe(unzip.Extract({path:'./'}))
    });
}
2
Mtl Dev

別の実例:

var zlib = require('zlib');
var tar = require('tar');
var ftp = require('ftp');

var files = [];

var conn = new ftp();
conn.on('connect', function(e) 
{
    conn.auth(function(e) 
    {
        if (e)
        {
            throw e;
        }
        conn.get('/tz/tzdata-latest.tar.gz', function(e, stream) 
        {
            stream.on('success', function() 
            {
                conn.end();

                console.log("Processing files ...");

                for (var name in files)
                {
                    var file = files[name];

                    console.log("filename: " + name);
                    console.log(file);
                }
                console.log("OK")
            });
            stream.on('error', function(e) 
            {
                console.log('ERROR during get(): ' + e);
                conn.end();
            });

            console.log("Reading ...");

            stream
            .pipe(zlib.createGunzip())
            .pipe(tar.Parse())
            .on("entry", function (e) 
            {    
                var filename = e.props["path"];
                console.log("filename:" + filename);
                if( files[filename] == null )
                {
                    files[filename] = "";
                }
                e.on("data", function (c) 
                {
                    files[filename] += c.toString();
                })    
            });
        });
    });
})
.connect(21, "ftp.iana.org");