Search code examples
javascriptnode.jsunzip

unzipper ignores empty directory


I am a Japanese Web Developer.

I am not good at English, sorry.

https://www.npmjs.com/package/unzipper

I am using this library.

Here is my code.

// unzip module
import fs from 'fs-extra'
import unzipper from 'unzipper'
import Promise from 'bluebird'

export default ({ inputFilePath, outputFilePath }) => {
  return new Promise(async (resolve, reject, onCancel) => {
    try {
      await streamPromise(fs.createReadStream(inputFilePath).pipe(unzipper.Extract({ path: outputFilePath })))
        .then(resolve)
    } catch (error) {
      reject(error)
    }
  })
}

const streamPromise = (stream) => {
  return new Promise((resolve, reject) => {
    stream.on('end', () => {
      resolve('end')
    })
    stream.on('finish', () => {
      resolve('finish')
    })
    stream.on('error', (error) => {
      reject(error)
    })
  })
}

But directory which has no file inside, won't be copied.

Any way to fix this?


Solution

    • You want to unzip a zip file using unzipper.
    • You want to also export the directories without files.

    If my understanding is correct, how about this modification? I think that there are several answers for your situation. So please think of this as just one of them.

    Modification point:

    • In this modification, when the file type is "Directory", a new Directory is created. By this, the directory without files can be exported.

    Modified script:

    Please modify as follows.

    // unzip module
    import fs from 'fs-extra'
    import unzipper from 'unzipper'
    import Promise from 'bluebird'
    import path from 'path' // Added
    
    // Modified
    export default ({ inputFilePath, outputFilePath }) => {
      return new Promise(async (resolve, reject, onCancel) => {
        try {
          await streamPromise(fs.createReadStream(inputFilePath).pipe(unzipper.Parse()), outputFilePath)
            .then(resolve)
        } catch (error) {
          reject(error)
        }
      })
    }
    
    // Modified
    const streamPromise = (stream, outputFilePath) => {
      return new Promise((resolve, reject) => {
        stream.on("entry", entry => {
          const fileName = entry.path;
          const type = entry.type;
          if (type == "Directory") {
            fs.mkdirSync(path.join(outputFilePath, fileName));
          } else if (type == "File") {
            entry.pipe(fs.createWriteStream(path.join(outputFilePath, fileName)));
          }
        });
        stream.on("end", () => {
          resolve("end");
        });
        stream.on("finish", () => {
          resolve("finish");
        });
        stream.on("error", error => {
          reject(error);
        });
      });
    };
    

    Reference:

    In my environment, I could confirm that the modified script worked. But in your environment, the script didn't work, I apologize.