Подтвердить что ты не робот

Самый простой способ загрузить и распаковать файлы в кросс-платформе Node.js?

Просто найдите простое решение для загрузки и распаковки файлов .zip или .tar.gz в Node.js в любой операционной системе.

Не уверен, что он встроен, или мне нужно использовать отдельную библиотеку. Есть идеи? Ищете только пару строк кода, поэтому, когда следующий zip файл приходит, который я хочу загрузить в node, это не проблема. Почувствуйте, как это должно быть легко и/или встроено, но я ничего не могу найти. Спасибо!

4b9b3361

Ответ 1

Оформить заказ adm-zip.

ADM-ZIP - это чистая реализация JavaScript для сжатия ZIP-данных для NodeJS.

Библиотека позволяет вам:

распаковать zip файлы непосредственно на диск или в буферы памяти сжать файлы и сохранять их на диск в формате .zip или в сжатых буферах обновить содержимое/добавить новые/удалить файлы из существующего .zip

Ответ 2

Node имеет встроенную поддержку gzip и deflate через модуль zlib:

var zlib = require('zlib');

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

    console.log(result);
});

Изменить: Вы можете даже pipe передавать данные непосредственно через, например. Gunzip (используя request):

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-архивов существует файл tar-модуля Isaacs, который используется npm.

Изменить 2: Обновленный ответ как zlib не поддерживает формат zip. Это будет работать только для gzip.

Ответ 3

yauzl - это надежная библиотека для распаковки. Принципы проектирования:

  • Следуйте спецификации. Не сканировать локальные заголовки файлов. Прочтите центральный каталог метаданных файла.
  • Не блокируйте поток JavaScript. Использовать и предоставлять асинхронные API.
  • Сохранять использование памяти под контролем. Не пытайтесь одновременно копировать все файлы в ОЗУ.
  • Никогда не сбой (если используется правильно). Не позволяйте malformed zip файлам сбивать клиентские приложения, которые пытаются поймать ошибки.
  • Поймать записи небезопасных файлов. Запись в zip файле вызывает ошибку, если имя файла начинается с "/" или/[A-Za-z]://или содержит сегменты пути ".." или "\" (по спецификации).

В настоящее время имеется 97% охвата тестирования.

Ответ 4

Это 2017 год (26 октября, если быть точным).

Для древней и широко распространенной технологии, такой как unzip, я ожидаю, что там будет существовать довольно популярная, зрелая библиотека node.js unzip, которая "застойна" и "не поддерживается", потому что она "завершена".

Однако большинство библиотек кажутся либо ужасными, либо компромиссными, как всего несколько месяцев назад. Это довольно важно... поэтому я просмотрел несколько распакованных библиотек, прочитал их документы и попробовал свои примеры, чтобы попытаться выяснить WTF. Например, я пробовал эти:

Верхняя Рекомендация: yauzl

Отлично работает для полностью загруженного файла. Не так хорошо для потоковой передачи.

Хорошо документировано. Работает хорошо. Имеет смысл.

2nd Pick: 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).
  • использует какой-то существующий код из популярной библиотеки
  • не содержит слишком много бессмысленного hipster или 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()
  });

Pros

  • Кажется, работает аналогично node-stream-zip, но меньше контроля
  • Более функциональный fork unzip
  • Кажется, что он запускается серийно, а не параллельно.

против

  • Кухонная мойка? Просто включает в себя массу вещей, которые не связаны с распаковкой.
  • Читает весь файл (куском, что хорошо), а не просто случайные запросы

Ответ 5

Я попробовал несколько из unzip-библиотек nodejs, включая adm-zip и unzip, а затем установил на extract-zip, который является оберткой вокруг yauzl. Казалось, что проще всего реализовать.

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

var extract = require('extract-zip')
extract(zipfile, { dir: outputPath }, function (err) {
   // handle err
})

Ответ 6

Я долго ждал этого и не нашел простого рабочего примера, но на основе этих ответов я создал функцию 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);
};

Ответ 7

Другой рабочий пример:

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

Ответ 8

Я нашел успех со следующим, работает с .zip
(Упрощается здесь для публикации: нет проверки ошибок и просто распаковывает все файлы в текущую папку)

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