web-dev-qa-db-fra.com

Extraire Zip dans le nœud du dossier via express

J'essaie de trouver un exemple où je peux envoyer un Zip (comme via postman) et obtenir ce Zip dans mon gestionnaire et unzip le dossier si spécifié Je n'ai pas trouvé beaucoup d'exemples de compression en utilisant express Je veux le décompresser dans le chemin web/app

J'essaie quelque chose comme ce qui suit qui ne fonctionne pas pour moi, le fichier Zip n'est pas décompressé dans le dossier spécifié, aucune idée de ce que je fais mal?

https://nodejs.org/api/zlib.html#zlib_zlib

var zlib = require('zlib');
var fs = require('fs');
const dir = path.join(__dirname, 'web/app/');

if (req.file.mimetype === 'application/Zip') {

    var unzip = zlib.createUnzip();

    var read = fs.createReadStream(req.file);
    var write = fs.createWriteStream(dir);
    //Transform stream which is unzipping the zipped file
    read.pipe(unzip).pipe(write);   
    console.log("unZipped Successfully");

}

Tout exemple de travail sera très utile, ou une référence où peut avoir un problème ...

pendant le débogage, je vois que le code a échoué

var read = fs.createReadStream(req.file);

aucune idée pourquoi?

J'ai aussi essayé avec

var read = fs.createReadStream(req.file.body);

le problème que je ne vois pas l'erreur, la raison, etc.

quand je le change en

var read = fs.createReadStream(req.file.buffer);

le programme ne se ferme pas et j'ai pu l'exécuter jusqu'au consignateur console.log("unZipped Successfully"); mais rien ne se passe ...

s'il y a un exemple avec https://www.npmjs.com/package/yauzl yauzl et multer dans mon contexte, ce sera génial

update- c'est la demande du facteur

 enter image description here

9
user4445419

Tout d'abord, zlib ne prend pas en charge l'extraction de fichiers Zip

Je recommande formidable pour le traitement des fichiers car

  1. sa bataille testée
  2. le plus largement utilisé
  3. évite l'écriture du code de plaque standard, comme la lecture de flux de fichiers à partir d'une requête, le stockage et la gestion des erreurs
  4. facilement configurable

Conditions préalables
Installer les dépendances en utilisant npm i -S extract-Zip formidable express ou yarn add extract-Zip formidable express

Bare solution minimale pour votre problème avec formidable et extract-Zip

const express = require('express');
const fs = require('fs');
const extract = require('extract-Zip')
const formidable = require('formidable');
const path = require('path');
const uploadDir = path.join(__dirname, '/uploads/');
const extractDir = path.join(__dirname, '/app/');
if (!fs.existsSync(uploadDir)) {
  fs.mkdirSync(uploadDir);
}
if (!fs.existsSync(extractDir)) {
  fs.mkdirSync(extractDir);
}

const server = express();

const uploadMedia = (req, res, next) => {
  const form = new formidable.IncomingForm();
  // file size limit 100MB. change according to your needs
  form.maxFileSize = 100 * 1024 * 1024;
  form.keepExtensions = true;
  form.multiples = true;
  form.uploadDir = uploadDir;

  // collect all form files and fileds and pass to its callback
  form.parse(req, (err, fields, files) => {
    // when form parsing fails throw error
    if (err) return res.status(500).json({ error: err });

    if (Object.keys(files).length === 0) return res.status(400).json({ message: "no files uploaded" });

    // Iterate all uploaded files and get their path, extension, final extraction path
    const filesInfo = Object.keys(files).map((key) => {
      const file = files[key];
      const filePath = file.path;
      const fileExt = path.extname(file.name);
      const fileName = path.basename(file.name, fileExt);
      const destDir = path.join(extractDir, fileName);

      return { filePath, fileExt, destDir };
    });

    // Check whether uploaded files are Zip files
    const validFiles = filesInfo.every(({ fileExt }) => fileExt === '.Zip');

    // if uploaded files are not Zip files, return error
    if (!validFiles) return res.status(400).json({ message: "unsupported file type" });

    res.status(200).json({ uploaded: true });

    // iterate through each file path and extract them
    filesInfo.forEach(({filePath, destDir}) => {
      // create directory with timestamp to prevent overwrite same directory names
      extract(filePath, { dir: `${destDir}_${new Date().getTime()}` }, (err) => {
        if (err) console.error('extraction failed.');
      });
    });
  });

  // runs when new file detected in upload stream
  form.on('fileBegin', function (name, file) {
    // get the file base name `index.css.Zip` => `index.html`
    const fileName = path.basename(file.name, path.extname(file.name));
    const fileExt = path.extname(file.name);
    // create files with timestamp to prevent overwrite same file names
    file.path = path.join(uploadDir, `${fileName}_${new Date().getTime()}${fileExt}`);
  });
}

server.post('/upload', uploadMedia);

server.listen(3000, (err) => {
  if (err) throw err;
});

Cette solution fonctionne pour les téléchargements de fichiers uniques/multiples. Le seul problème de cette solution est que les types de fichiers incorrects seront téléchargés dans le répertoire uploaded malgré une erreur de lancement du serveur.

Pour tester avec le facteur: postman image

2
REDDY PRASAD

Conditions préalables :

  1. npm i express unzipper multiparty bluebird
  2. Créez le répertoire app/web dans la racine de votre projet (ou vous pouvez automatiser la création si vous le souhaitez).
  3. Placez tous ces fichiers dans un répertoire.
  4. Version de nœud qui prend en charge async/await (7.6+ autant que je sache)

server.js :

const express = require('express');
const Promise = require('bluebird');
const fs = require('fs');
const writeFile = Promise.promisify(fs.writeFile);

const { parseRequest, getFile } = require('./multipart');
const { extractFiles } = require('./Zip')

const EXTRACT_DIR = 'web/app';

const app = express();

const uploadFile = async (req, res, next) => {
  try {
    const body = await parseRequest(req);
    const bodyFile = getFile(body, 'file');
    if (!/\.Zip$/.test(bodyFile.originalFilename)) {
      res.status(200).json({ notice: 'not a Zip archive, skipping' })
      return;
    }
    const archiveFiles = await extractFiles(bodyFile);

    await Promise.each(archiveFiles, async (file) => {
      await writeFile(EXTRACT_DIR + '/' + file.path, file.buffer);
    })
    res.status(200).end();
  } catch (e) {
    res.status(500).end();
  }
};

app.post('/files', uploadFile);

app.listen(3000, () => {
  console.log('App is listening on port 3000');
});

multipart.js

const Promise = require('bluebird');
const { Form } = require('multiparty');

function parseRequest (req, options) {
    return new Promise((resolve, reject) => {
        const form = new Form(options)
        form.parse(req, (err, fields, files) => {
            if (err) {
                return reject(err);
            }
            return resolve({ fields, files });
        });
    });
}

function getFile (body, field) {
    const bodyFile = body.files[field];
    const value = bodyFile ? bodyFile[0] : null;
    return value || null;
}

module.exports = {
    parseRequest,
    getFile,
};

Zip.js

const unzip = require('unzipper');
const fs = require('fs');

async function extractFiles (file) {
    const files = [];
    await fs.createReadStream(file.path).pipe(unzip.Parse()).on('entry', async entry => {
    // Cleanup system hidden files (or drop this code if not needed)
        if (
            entry.type !== 'File'
            || /^__MACOSX/.test(entry.path)
            || /.DS_Store/.test(entry.path)
        ) {
            entry.autodrain()
            return
        }
        const pathArr = entry.path.split('/');
        const path = entry.path;
        const buffer = await entry.buffer();
        files.Push({ buffer, path, originalFilename: pathArr[pathArr.length - 1] });
    }).promise();
    return files;
}

module.exports = {
    extractFiles,
};

Utilisation :

  1. Démarrer un serveur avec node server
  2. Envoyez votre fichier dans le champ file dans la requête (clé file dans le facteur). Exemple en curl curl -XPOST -F 'file=@../ttrra-dsp-agency-api/banner.Zip' 'localhost:3000/files')

Inconvénients :

  1. Les fichiers décompressés sont stockés dans la mémoire tampon, donc cette méthode ne fonctionne pas bien et n'est pas recommandé pour les grandes archives.
2
coockoo

Sans un exemple complet, il est difficile de dire quel est le véritable problème. Mais selon Express docs , il est écrit: 

Dans Express 4, req.files n'est plus disponible sur l'objet req par défaut. Pour accéder aux fichiers téléchargés sur l'objet req.files, utilisez middleware de traitement en plusieurs parties comme busboy, multer, formidable, multiparty, connect-multiparty ou pez.

Donc, si vous n'utilisez pas de bibliothèque middleware pour gérer le téléchargement de fichiers, il est difficile de dire quelle est la valeur de req.file

Je suis aussi un peu inquiet que vous essayiez d'utiliser zlib pour décompresser un fichier Zip, car la library ne supporte que gzip.

Le module zlib fournit une fonctionnalité de compression implémentée à l'aide de Gzip et Deflate/Gonfler

Vous voulez vérifier pour req.file.mimetype === 'application/gzip'

Voici quelques articles liés à la décompression de fichiers Zip:

2
jjbskir