Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/39.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
跨平台下载和解压Node.js中文件的最简单方法?_Node.js_Zip - Fatal编程技术网

跨平台下载和解压Node.js中文件的最简单方法?

跨平台下载和解压Node.js中文件的最简单方法?,node.js,zip,Node.js,Zip,只是想寻找一个简单的解决方案,在任何操作系统上下载和解压缩Node.js中的.zip或.tar.gz文件 不确定这是内置的还是我必须使用单独的库。有什么想法吗?只需要几行代码,所以当下一个zip文件出现时,我想在node中下载它,这是一个很简单的问题。感觉这应该很容易和/或内置,但我找不到任何东西。谢谢 结帐 ADM-ZIP是一个纯JavaScript实现,用于NodeJS的ZIP数据压缩 该库允许您: 将zip文件直接解压缩到磁盘或内存缓冲区中 压缩文件并以.zip格式或压缩缓冲区将其存储到

只是想寻找一个简单的解决方案,在任何操作系统上下载和解压缩Node.js中的
.zip
.tar.gz
文件

不确定这是内置的还是我必须使用单独的库。有什么想法吗?只需要几行代码,所以当下一个zip文件出现时,我想在node中下载它,这是一个很简单的问题。感觉这应该很容易和/或内置,但我找不到任何东西。谢谢

结帐

ADM-ZIP是一个纯JavaScript实现,用于NodeJS的ZIP数据压缩

该库允许您:

  • 将zip文件直接解压缩到磁盘或内存缓冲区中
  • 压缩文件并以
    .zip
    格式或压缩缓冲区将其存储到磁盘
  • 更新现有
    .zip文件的内容/添加新文件/删除文件

节点内置了对gzip的支持,并通过:

编辑:您甚至可以直接通过
管道
数据,例如
Gunzip
(使用):

对于tar档案,有一个由npm使用的Isaacs


编辑2:更新答案,因为
zlib
不支持
zip
格式。这仅适用于
gzip

另一个工作示例:

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");
是一个强大的解压库。设计原则:

  • 遵循规范。不要扫描本地文件头。读取文件元数据的中心目录
  • 不要阻塞JavaScript线程。使用并提供异步API
  • 控制内存使用。不要试图一次在RAM中缓冲整个文件
  • 切勿碰撞(如果使用正确)。不要让格式错误的zip文件导致试图捕获错误的客户端应用程序宕机
  • 捕获不安全的文件名条目。如果zip文件条目的文件名以“/”或“/[A-Za-z]://开头,或包含“.”路径段或“\”(根据规范),则会引发错误

目前有97%的测试覆盖率。

我期待了很长一段时间,没有发现简单的工作示例,但基于这些答案,我创建了
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);
};

我在以下方面获得了成功,与.zip一起工作
(此处简化发布:无错误检查&只需将所有文件解压缩到当前文件夹)


我尝试了一些nodejs解压库,包括adm-zip和unzip,然后选择了extract-zip,它是yauzl的包装器。似乎是最简单的实现

现在是2017年(确切地说是10月26日)

对于一种古老而普及的技术,比如解压,我希望存在一个相当流行、成熟的node.js解压库,它是“停滞的”和“未维护的”,因为它是“完整的”

然而,大多数库要么看起来非常糟糕,要么最近像几个月前一样有提交。这是相当令人担忧的。。。所以我浏览了几个解压库,阅读了它们的文档,并尝试了它们的示例,试图找出WTF。例如,我尝试了以下方法:

  • 约书亚沃尔夫酒店/
  • 安特尔/
  • 茨琼森/
  • 埃文斯菲尔德/
  • 斯图克/
  • 克里斯科瓦尔/
更新2020:还没有尝试过,但也有

顶级推荐:
yauzl
适用于完全下载的文件。不适合流媒体

有据可查。效果很好。有道理

第二个选择:
节点流zip
安泰尔的似乎是最好的

安装:

npm install --save node-stream-zip
npm install --save unzipper
用法:

'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));
      }
    );
  });
});
'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()
  });
安全警告

不确定此操作是否会检查
entry.name
是否存在恶意创建的路径,这些路径可能无法正确解析(例如
。/../../foo
/etc/passwd

您可以通过比较
/\.\./.test(path.relative('./to/dir',path.resolve('./to/dir',entry.name))
轻松检查这一点

优点(为什么我认为它是最好的?)

  • 可以解压普通文件(可能不是一些具有奇怪扩展名的疯狂文件)
  • 能流
  • 似乎不必加载整个zip来读取条目
  • 有普通JavaScript中的示例(未编译)
  • 不包括厨房水槽(即url加载、S3或db层)
  • 使用流行库中的一些现有代码
  • 代码中没有太多毫无意义的时髦或忍者
缺点

  • 像饥饿的河马一样吞咽错误
  • 抛出字符串而不是错误(无堆栈跟踪)
  • zip.extract()
亚军:节点拉链 安装:

npm install --save node-stream-zip
npm install --save unzipper
用法:

'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));
      }
    );
  });
});
'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()
  });
专业人士

  • 似乎以类似于
    节点流zip
    的方式工作,但控制较少
  • 更具功能的
    解压叉
  • 似乎是串行运行,而不是并行运行
缺点

  • 厨房水槽多少钱?只是包含了大量与解压无关的东西
  • 读取整个文件(按块,这很好),而不仅仅是随机查找

您也可以使用“解压”简单地提取现有的zip文件。它适用于任何大小的文件,您需要将其添加为来自的依赖项

fs.createReadStream(filePath).pipe(unzip.Extract({path:moveIntoFolder})).on('close',function(){
//解压后做什么
回调();

});下载并提取
.tar.gz

const https = require("https");
const tar = require("tar");

https.get("https://url.to/your.tar.gz", function(response) {
  response.pipe(
    tar.x({
      strip: 1,
      C: "some-dir"
    })
  );
});
结帐


不,这两个例子都不起作用。js的zlib模块只用于表示单一资源的流和缓冲区;不是zip或tar档案。你似乎误解了这个问题。他没有试图解压缩单个流或单个文件。他正试图从整个ar中提取文件
import gunzip from 'gunzip-file';

const unzipAll = async () => {
  try {
    const compFiles = fs.readdirSync('tmp')
    await Promise.all(compFiles.map( async file => {
      if(file.endsWith(".gz")){
        gunzip(`tmp/${file}`, `tmp/${file.slice(0, -3)}`)
      }
    }));
  }
  catch(err) {
    console.log(err)
  }
}