Node.js kullanarak tüm dizini ZIP haline getirmeniz gerekiyor


115

Node.js kullanarak tüm dizini sıkıştırmam gerekiyor. Şu anda node-zip kullanıyorum ve işlem her çalıştığında geçersiz bir ZIP dosyası oluşturuyor ( bu Github sorunundan da görebileceğiniz gibi ).

Bir dizini ZIP açmama izin verecek başka, daha iyi bir Node.js seçeneği var mı?

DÜZENLEME: Arşivleyiciyi kullanmayı bıraktım

writeZip = function(dir,name) {
var zip = new JSZip(),
    code = zip.folder(dir),
    output = zip.generate(),
    filename = ['jsd-',name,'.zip'].join('');

fs.writeFileSync(baseDir + filename, output);
console.log('creating ' + filename);
};

parametreler için örnek değer:

dir = /tmp/jsd-<randomstring>/
name = <randomstring>

GÜNCELLEME: Kullandığım uygulama hakkında soru soranlar için, indiricime bir bağlantı :


3
Twitter'dan biri child_process API'yi önerdi ve sistem ZIP'sini
çağırın

1
Child_process yaklaşımını denedim. İki uyarısı var. 1) unix zipkomutu, sıkıştırılmış dosyadaki mevcut çalışma dizininin tüm üst klasör hiyerarşisini içerir. Bu senin için uygun olabilir, benim için değildi. Ayrıca child_process'teki mevcut çalışma dizinini değiştirmek sonuçları bir şekilde etkilemez. 2) Bu sorunu aşmak için, kullanmak zorunda pushdsize zip ve olacak klasöre atlamak için zip -r, ancak o zamandan beri pushd bin / bash içine değil, yerleşik / da kullanım / bin / bash gerek sh. Benim özel durumumda bu mümkün değildi. Sadece aklınızda bulunsun.
johnozbay

2
@johnozbay düğümünün child_process.execapi'si, komutu çalıştırmak istediğiniz cwd'yi belirlemenize izin verir. CWD'nin değiştirilmesi, ana klasör hiyerarşisi sorununu çözer. Ayrıca ihtiyaç duymama sorununu da giderir pushd. Child_process'i tamamen tavsiye ederim.
Govind Rai

1
child_process api kullanan stackoverflow.com/a/49970368/2757916 yerel nodejs çözümü. 2 satır kod. Üçüncü şahıs kütüphaneleri yok.
Govind Rai

@GovindRai Çok teşekkürler!
johnozbay

Yanıtlar:


137

Archiver lib'yi kullanmaya başladım . Harika çalışıyor.

Misal

var file_system = require('fs');
var archiver = require('archiver');

var output = file_system.createWriteStream('target.zip');
var archive = archiver('zip');

output.on('close', function () {
    console.log(archive.pointer() + ' total bytes');
    console.log('archiver has been finalized and the output file descriptor has closed.');
});

archive.on('error', function(err){
    throw err;
});

archive.pipe(output);

// append files from a sub-directory, putting its contents at the root of archive
archive.directory(source_dir, false);

// append files from a sub-directory and naming it `new-subdir` within the archive
archive.directory('subdir/', 'new-subdir');

archive.finalize();

1
Bunun nasıl yapılacağına dair herhangi bir örnek yok gibi görünüyor, ne yaptığınızı paylaşır mısınız?
Sinetheta

1
archiver, maalesef şu anda dosya adlarında Unicode karakterlerini desteklemiyor. Github.com/ctalkington/node-archiver/issues/90 adresine bildirildi .
Eye

2
Tüm dosyaları ve dizinleri özyinelemeli olarak nasıl dahil edebilirim (ayrıca gizli dosyaları / dizinleri)?
Ionică Bizău

12
Archiver bunu şimdi daha da basit hale getiriyor. Bulk () yöntemini kullanmak yerine artık directory () kullanabilirsiniz: npmjs.com/package/archiver#directory-dirpath-destpath-data
Josh Feldman

14
.bulkkullanımdan kaldırıldı
chovy

55

Yeni bir şey gösteriyormuş gibi yapmıyorum, sadece kodlarında Promise işlevlerini kullanmaktan hoşlananlar için (benim gibi) çözümleri yukarıda özetlemek istiyorum.

const archiver = require('archiver');

/**
 * @param {String} source
 * @param {String} out
 * @returns {Promise}
 */
function zipDirectory(source, out) {
  const archive = archiver('zip', { zlib: { level: 9 }});
  const stream = fs.createWriteStream(out);

  return new Promise((resolve, reject) => {
    archive
      .directory(source, false)
      .on('error', err => reject(err))
      .pipe(stream)
    ;

    stream.on('close', () => resolve());
    archive.finalize();
  });
}

Umarım birine yardımcı olur;)


burada "dışarıda" tam olarak ne var? kaynak dizinin yolu olduğunu varsayıyorum
Dreams

@Tarun tam zip yolu gibi: /User/mypc/mydir/test.zip
D.Dimitrioglo

Zip dosyası açılamıyor. İşleme izin verilmiyor
Jake

@ ekaj_03 lütfen belirtilen dizin için yeterli haklara sahip olduğunuzdan emin olun
D.Dimitrioglo

1
@ D.Dimitrioglo hepsi iyi. Kaynak dir sorun buydu. Teşekkürler :)
Jake

19

child_processBunu gerçekleştirmek için Düğümün yerel API'sini kullanın.

Üçüncü şahıs kitaplarına gerek yok. İki satır kod.

const child_process = require("child_process");
child_process.execSync(`zip -r DESIRED_NAME_OF_ZIP_FILE_HERE *`, {
  cwd: PATH_TO_FOLDER_YOU_WANT_ZIPPED_HERE
});

Eşzamanlı API kullanıyorum. child_process.exec(path, options, callback)Eşzamansız ihtiyacınız varsa kullanabilirsiniz . İsteklerinizi daha iyi ayarlamak için CWD'yi belirtmekten çok daha fazla seçenek vardır. Exec / execSync belgelerine bakın .


Lütfen dikkat: Bu örnek, sisteminizde zip yardımcı programının kurulu olduğunu varsayar (en azından OSX ile birlikte gelir). Bazı işletim sistemlerinde yardımcı program kurulu olmayabilir (yani, AWS Lambda çalışma zamanı yoktur). Bu durumda, zip yardımcı programı ikili dosyasını buradan kolayca edinebilir ve uygulama kaynak kodunuzla birlikte paketleyebilirsiniz (AWS Lambda için bunu bir Lambda Katmanında da paketleyebilirsiniz) veya bir üçüncü taraf modülü kullanmanız gerekir (NPM'de bol miktarda var). ZIP yardımcı programı onlarca yıldır denendiği ve test edildiği için eski yaklaşımı tercih ediyorum.


10
Ne yazık ki sadece sahip olan sistemlerde çalışır zip.
janpio


mantıklı geliyor, ancak yanılmıyorsam bu, Windows kullanıcılarını tekrar alt üst ediyor. Lütfen Windows kullanıcılarını düşünün!
Mathijs Segers

@MathijsSegers haha! bu yüzden Windows kullanıcılarının da alabilmesi için ikiliye bir bağlantı ekledim! :)
Govind Rai

Bunun bir bilgisayar dizini yerine bir proje içindeki bir dizin için çalışmasını sağlamanın bir yolu var mı?
Matt Croak

13

Archive.bulkartık kullanımdan kaldırıldı, bunun için kullanılacak yeni yöntem glob :

var fileName =   'zipOutput.zip'
var fileOutput = fs.createWriteStream(fileName);

fileOutput.on('close', function () {
    console.log(archive.pointer() + ' total bytes');
    console.log('archiver has been finalized and the output file descriptor has closed.');
});

archive.pipe(fileOutput);
archive.glob("../dist/**/*"); //some glob pattern here
archive.glob("../dist/.htaccess"); //another glob pattern
// add as many as you like
archive.on('error', function(err){
    throw err;
});
archive.finalize();

2
Bunu merak ediyorlardı, toplu işlemin kullanımdan kaldırıldığını söylediler ancak bunun yerine hangi işlevi kullanacaklarını önermediler.
jarodsmk

1
"Kaynak" dizini nasıl belirtirsiniz?
Dreams

Aşağıdaki yaklaşımı bir kez deneyin: jsonworld.wordpress.com/2019/09/07/…
Soni Kumari

2020: archive.directory () çok daha basit!
OhadR


9

Bu, klasörü tek satırda sıkıştıran başka bir kitaplıktır: zip-local

var zipper = require('zip-local');

zipper.sync.zip("./hello/world/").compress().save("pack.zip");

4
Benim için her zaman 'sıfır bayt' dosyası oluşturan, internette bulunan veya yukarıda bahsedilen düzinelerce diğerlerinin aksine bir cazibe gibi çalıştı
Sergey Pleshakov

4

Sonucu yanıt nesnesine yönlendirmek için (yerel olarak depolamak yerine zip dosyasını indirmenin gerekli olduğu senaryolar)

 archive.pipe(res);

Sam'in dizinin içeriğine erişme ipuçları benim için çalıştı.

src: ["**/*"]

3

Adm-zip, mevcut bir arşivi https://github.com/cthackers/adm-zip/issues/64 sıkıştırmanın yanı sıra ikili dosyaların sıkıştırılmasında bozulma sorunları yaşıyor .

Ayrıca node-zip https://github.com/daraosn/node-zip/issues/4 ile ilgili sıkıştırma bozulması sorunlarıyla karşılaştım

node-archiver, sıkıştırmak için iyi çalışan tek şeydir, ancak herhangi bir sıkıştırmayı açma işlevi yoktur.


1
Hangi düğüm arşivleyicisinden bahsediyorsunuz? : github.com/archiverjs/node-archiver; github.com/richardbolt/node-archiver
biphobe

@firian Archiver demedi, Adm-zip dedi.
Francis Pelland

5
@FrancisPelland Umm, son cümlede " node-archiver işe yarayan tek şey " yazdı - ben de bunu kastediyorum.
biphobe


2

İhtiyacınız olanı içeren bu küçük kütüphaneyi buldum.

npm install zip-a-folder

const zip-a-folder = require('zip-a-folder');
await zip-a-folder.zip('/path/to/the/folder', '/path/to/archive.zip');

https://www.npmjs.com/package/zip-a-folder


Zip klasörü yapmak için parametre eklemek mümkün müdür? sıkıştırılmış seviye ve boyut gibi öyleyse bunu nasıl yapmalı?
Trang D

1

Yana archiveruzun süre WebPack yeni sürümü ile uyumlu değildir, ben kullanmanızı öneririz zip-lib .

var zl = require("zip-lib");

zl.archiveFolder("path/to/folder", "path/to/target.zip").then(function () {
    console.log("done");
}, function (err) {
    console.log(err);
});

0

Basit bir şekilde deneyebilirsiniz:

Kurulum zip-dir:

npm install zip-dir

ve kullan

var zipdir = require('zip-dir');

let foldername =  src_path.split('/').pop() 
    zipdir(<<src_path>>, { saveTo: 'demo.zip' }, function (err, buffer) {

    });

zip klasörü yapmak için parametreler eklemek mümkün mü? sıkıştırılmış seviye ve boyut gibi öyleyse bunu nasıl yapmalı?
Trang D

0

Projem aracılığıyla yeniden düzenleme çok fazla çaba gerektireceğinden, JSZip'i taklit etmek için arşivleyiciyi paketledim. Archiver'ın en iyi seçenek olmayabileceğini anlıyorum, ama işte burası.

// USAGE:
const zip=JSZipStream.to(myFileLocation)
    .onDone(()=>{})
    .onError(()=>{});

zip.file('something.txt','My content');
zip.folder('myfolder').file('something-inFolder.txt','My content');
zip.finalize();

// NodeJS file content:
    var fs = require('fs');
    var path = require('path');
    var archiver = require('archiver');

  function zipper(archive, settings) {
    return {
        output: null,
        streamToFile(dir) {
            const output = fs.createWriteStream(dir);
            this.output = output;
            archive.pipe(output);

            return this;
        },
        file(location, content) {
            if (settings.location) {
                location = path.join(settings.location, location);
            }
            archive.append(content, { name: location });
            return this;
        },
        folder(location) {
            if (settings.location) {
                location = path.join(settings.location, location);
            }
            return zipper(archive, { location: location });
        },
        finalize() {
            archive.finalize();
            return this;
        },
        onDone(method) {
            this.output.on('close', method);
            return this;
        },
        onError(method) {
            this.output.on('error', method);
            return this;
        }
    };
}

exports.JSzipStream = {
    to(destination) {
        console.log('stream to',destination)
        const archive = archiver('zip', {
            zlib: { level: 9 } // Sets the compression level.
        });
        return zipper(archive, {}).streamToFile(destination);
    }
};
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.