【问题标题】:Unzipping a password protected file in Node.js在 Node.js 中解压缩受密码保护的文件
【发布时间】:2014-07-18 13:55:36
【问题描述】:

是否有一个库可以用来解压缩受密码保护的文件(网站在下载文件时让我在文件上输入密码)?有很多库可以解压缩普通文件,但我找不到可以用密码解压的库。

Here 我找到了一些有用的初学者。但我宁愿不使用child_process 并使用内置的 unix 解压缩功能,但这可能是我最后的手段。我什至会自行对加密代码进行操作,但我什至无法找出如何确定加密类型(这似乎很标准,因为我可以在终端中完成)。

再次,我宁愿不这样做,但恐怕这是我唯一的选择,所以我尝试了以下方法:

var fs = require('fs')
, unzip = require('unzip')
, spawn = require('child_process').spawn
, expand = function(filepath, cb) {
     var self = this
     , unzipStream = fs.createReadStream(filepath).pipe(unzip.Parse())
     , xmlData = '';

     unzipStream.on('entry', function (entry) {
            var filename = entry.path;
           // first zip contains files and one password protected zipfile. 
           // Here I can just do pipe(unzip.Parse()) again, but then i just get a giant encoded string that I don't know how to handle, so i tried other things bellow.
           if(filename.match(/\.zip$/)){
                 entry.on('data', function (data) {
                     var funzip = spawn('funzip','-P','ThisIsATestPsswd','-');
                     var newFile = funzip.stdin.write(data);

            // more closing code...

然后我有点不知所措了。我尝试将newFile 写入文件,但那只是说[object]

然后我尝试通过将最后 3 行更改为来做一些更简单的事情

   fs.writeFile('./tmp/this.zip', data, 'binary');
   var newFile = spawn('unzip','-P','ThisIsATest','./tmp/this.zip');
   console.log('Data: ' + data);

但数据并没有什么用处,只是[object Object]。我不知道下一步该怎么做才能将这个新的解压缩文件放入工作文件或可读字符串。

我是Node 的超级新手,其他进程触发的所有异步/侦听器仍然有点令人困惑,所以如果其中任何一个没有意义,我很抱歉。非常感谢您的帮助!

编辑:


我现在添加了以下代码:

var fs = require('fs')
  , unzip = require('unzip')
  , spawn = require('child_process').spawn
  , expand = function(filepath, cb) {
    var self = this
    , unzipStream = fs.createReadStream(filepath)
      .pipe(unzip.Parse())
    , xmlData = '';

      unzipStream.on('entry', function (entry) {
        var filename = entry.path
            , type = entry.type // 'Directory' or 'File'
            , size = entry.size;
        console.log('Filename: ' + filename);

        if(filename.match(/\.zip$/)){
            entry.on('data', function (data) {
              fs.writeFile('./lib/mocks/tmp/this.zip', data, 'binary');
              var newFile = spawn('unzip','-P','ThisIsATestPassword', '-','../tmp/this.zip');
              newFile.stdout.on('data', function(data){
                 fs.writeFile('./lib/mocks/tmp/that.txt', data); //This needs to be something different
                    //The zip file contains an archive of files, so one file name shouldn't work
              });

           });
          } else { //Not a zip so handle differently }
       )};
    };

这似乎真的很接近我的需要,但是当文件被写入时,它所拥有的只是解压缩的选项列表:

UnZip 5.52 of 28 February 2005, by Info-ZIP.  Maintained by C. Spieler.  Send
bug reports using http://www.info-zip.org/zip-bug.html; see README for details.

Usage: unzip [-Z] [-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]
  Default action is to extract files in list, except those in xlist, to exdir;
  file[.zip] may be a wildcard.  -Z => ZipInfo mode ("unzip -Z" for usage).

  -p  extract files to pipe, no messages     -l  list files (short format)
  -f  freshen existing files, create none    -t  test compressed archive data
  -u  update files, create if necessary      -z  display archive comment
  -x  exclude files that follow (in xlist)   -d  extract files into exdir

modifiers:                                   -q  quiet mode (-qq => quieter)
  -n  never overwrite existing files         -a  auto-convert any text files
  -o  overwrite files WITHOUT prompting      -aa treat ALL files as text
  -j  junk paths (do not make directories)   -v  be verbose/print version info
  -C  match filenames case-insensitively     -L  make (some) names lowercase
  -X  restore UID/GID info                   -V  retain VMS version numbers
  -K  keep setuid/setgid/tacky permissions   -M  pipe through "more" pager
Examples (see unzip.txt for more info):
  unzip data1 -x joe   => extract all files except joe from zipfile data1.zip
  unzip -p foo | more  => send contents of foo.zip via pipe into program more
  unzip -fo foo ReadMe => quietly replace existing ReadMe if archive file newer

我不确定输入是否错误,因为这看起来像是解压缩的错误。或者,如果我只是写了错误的内容。我原以为它会像通常从控制台一样执行 - 只需将所有文件添加到目录中即可。虽然我希望能够从缓冲区中读取所有内容,但 - 选项似乎并没有这样做,所以我会满足于刚刚添加到目录中的文件。非常感谢任何有任何建议的人!

编辑 2


我能够得到这个工作,可能不是最好的方式,但它至少可以使用这条线:

var newFile = spawn('unzip', [ '-P','ThisIsATestPassword', '-d','./lib/tmp/foo','./lib/mocks/tmp/this.zip' ])

这会将所有文件解压缩到目录中,然后我就可以从那里读取它们。我的错误是第二个参数必须是一个数组。

【问题讨论】:

  • 使用console.log('Data: ', data);。您连接字符串和对象,因此对象转换为字符串[object Object]
  • 哇,帮了大忙,谢谢!
  • 当我使用这个日志时,我可以看到数据对象有_events: {data: function}。您如何触发该数据事件?我尝试了data.triggerEvent('data'),但只是想出了一个未定义的方法triggerEvent。
  • 可能更好的问题是在执行第二个选项之后,我要处理什么对象。它有一个 stdin 和一个 stdout 属性,这是否意味着它是一个 readStream 并且我可以使用相同的方法来访问其中的数据?
  • @CodySchaaf 看来您找到了正确的答案?如果是这样,我会将其发布为答案。

标签: node.js unzip zipfile


【解决方案1】:

我能够得到这个工作,可能不是最好的方式,但它至少可以使用这条线:

var newFile = spawn('unzip', [ '-P','ThisIsATestPassword', '-d','./lib/tmp/foo','./lib/mocks/tmp/this.zip' ])

这会将所有文件解压缩到目录中,然后我就可以从那里读取它们。我的错误是第二个参数必须是一个数组。

【讨论】:

    【解决方案2】:

    我使用unzipper 找到了解决方案。

    this blog粘贴代码

    const unzipper = require('unzipper');
    
    (async () => {
      try {
        const directory = await unzipper.Open.file('path/to/your.zip');
        const extracted = await directory.files[0].buffer('PASSWORD');
        console.log(extracted.toString()); // This will print the file content
      } catch(e) {
        console.log(e);
      }
    })();
    
    

    正如@codyschaaf 在他的回答中提到的,我们可以使用spawn 或其他一些child_process,但它们并不总是与操作系统无关。因此,如果我在生产中使用它,我将始终寻求与操作系统无关的解决方案(如果存在)。

    希望这对某人有所帮助。

    【讨论】:

    • 对我来说,这个解决方案卡在const extracted = await directory...........没有错误,只是执行停止
    【解决方案3】:

    我尝试了spawn 方法(spawnSync 实际上效果更好)。

    const result = spawnSync('unzip', ['-P', 'password', '-d', './files', './files/file.zip'], { encoding: 'utf-8' })
    
    

    尽管如此,这种方法并没有完全奏效,因为它引入了一个新错误:

    Archive:  test.zip
       skipping: file.png                need PK compat. v5.1 (can do v4.6)
    
    

    最后,我最终选择了7zip 方法:

    import sevenBin from '7zip-bin'
    import seven from 'node-7z'
    
    const zipPath = './files/file.zip'
    const downloadDirectory = './files'
    
    const zipStream = seven.extractFull(zipPath, downloadDirectory, {
      password: 'password',
      $bin: sevenBin.path7za
    })
    
    zipStream.on('end', () => {
      // Do stuff with unzipped content
    })
    

    【讨论】:

    • 我正在尝试这种 7zip 方法,但是我收到以下错误。似乎在 PATH 中找不到二进制文件? ` 错误:在 processTicksAndRejections (internal/process/task_queues.js:84) 的 onErrorNT (internal/child_process.js:470:16) 处的 Process.ChildProcess._handle.onexit (internal/child_process.js:268:19) 产生 7za ENOENT :21) `
    【解决方案4】:

    要解压受密码保护的多级压缩文件夹,请尝试以下代码。 我正在使用解压器 npm。

    unzipper.Open.file(contentPath + filename).then((mainDirectory) => {
    return new Promise((resolve, reject) => {
      let maindirPath = mainDirectory.files[0].path;
      let patharray = maindirPath.split("/")
      let temppath = destinationPath+patharray[0];
       fs.mkdirSync(temppath);//create parent Directory 
     
        // Iterate through every file inside there (this includes directories and files in subdirectories)
        for (let i = 0; i < mainDirectory.files.length; i++) {
            const file = mainDirectory.files[i];
            let filepath = Distinationpath + file.path
            
            if(file.path.endsWith("/")) {
                fs.mkdirSync(filepath);
            }
            else {
         
                file.stream(password).pipe(fs.createWriteStream(filepath))
                    .on('finished', resolve)
                    .on('error', reject);
            }
        }
    });
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-09
      • 2023-01-30
      • 1970-01-01
      相关资源
      最近更新 更多