Node.js를 사용하여 전체 디렉토리를 압축해야합니다.


107

Node.js를 사용하여 전체 디렉토리를 압축해야합니다. 현재 node-zip을 사용하고 있으며 프로세스가 실행될 때마다 잘못된 ZIP 파일이 생성됩니다 ( 이 Github 문제 에서 볼 수 있듯이 ).

디렉토리를 압축 할 수있는 또 다른 더 나은 Node.js 옵션이 있습니까?

편집 : 아카이버 를 사용하여 끝났습니다.

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);
};

매개 변수의 샘플 값 :

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

업데이트 : 내가 사용한 구현에 대해 묻는 사람들 을 위해 내 다운로더에 대한 링크가 있습니다 .


3
Twitter의 누군가가 child_process API를 제안하고 시스템 ZIP을 호출하기 만하면됩니다. nodejs.org/api/child_process.html
— commadelimited

1
나는 child_process 접근 방식을 시도했습니다. 두 가지주의 사항이 있습니다. 1) unix zip명령은 압축 파일에 현재 작업 디렉토리의 모든 상위 폴더 계층을 포함합니다. 이것은 당신에게 괜찮을지도 모르지만 그것은 나를위한 것이 아닙니다. 또한 child_process의 현재 작업 디렉토리를 변경해도 결과에 영향을 미치지 않습니다. 2) 이 문제를 극복하려면을 사용 pushd하여 zip 및을 폴더로 이동해야 zip -r하지만 pushd / bin / sh가 아닌 bash에 내장되어 있으므로 / bin / bash도 사용해야합니다. 내 특정한 경우에는 이것이 불가능했습니다. 그냥주의하세요.
— johnozbay

2
@johnozbay 노드의 child_process.execAPI를 사용하면 명령을 실행할 cwd를 지정할 수 있습니다. CWD를 변경하면 상위 폴더 계층 문제가 해결됩니다. 또한 필요하지 않은 문제도 해결합니다 pushd. 나는 child_process를 완전히 추천합니다.
— Govind Rai

1
stackoverflow.com/a/49970368/2757916 child_process api를 사용하는 네이티브 nodejs 솔루션. 2 줄의 코드. 타사 라이브러리가 없습니다.
— Govind Rai

@GovindRai 많은 감사합니다!
— johnozbay

답변:


124

결국 아카이버 lib 를 사용하게되었습니다 . 잘 작동합니다.

예

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 and naming it `new-subdir` within the archive (see docs for more options):
archive.directory(source_dir, false);
archive.finalize();

1
이 작업을 수행하는 방법에 대한 예가없는 것 같습니다. 수행 한 작업을 공유해 주시겠습니까?
— Sinetheta

1
불행히도 아카이버는 현재 파일 이름에서 유니 코드 문자를 지원하지 않습니다. 에보고 github.com/ctalkington/node-archiver/issues/90 .
— 아이

2
모든 파일과 디렉토리를 재귀 적으로 포함하는 방법 (숨겨진 파일 / 디렉토리도 포함)?
— Ionică Bizău

12
Archiver는 이제 이것을 더욱 간단하게 만듭니다. 오히려 대량 () 메소드를 사용하는 것보다, 당신은 지금 디렉토리 ()를 사용할 수 있습니다 npmjs.com/package/archiver#directory-dirpath-destpath-data
— 조쉬 펠드만

14
.bulk사용되지 않는 것입니다
— chovy은

46

나는 새로운 것을 보여주는 척하지 않고 (나와 같은) 코드에서 Promise 함수를 사용하는 것을 좋아하는 사람들을 위해 위의 솔루션을 요약하고 싶습니다.

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();
  });
}

누군가를 도울 수 있기를 바랍니다.)


여기서 "아웃"이란 정확히 무엇입니까? 나는 소스 디렉토리의 경로입니다 가정
— 꿈

/User/mypc/mydir/test.zip : 같은 @Tarun 전체 우편의 경로
— D.Dimitrioglo

zip 파일의 압축을 풀 수 없습니다. 조작은 허용되지 않습니다
— 제이크

@ ekaj_03 사용자가 지정한 디렉토리에 충분한 권한이 있는지 확인하십시오
— D.Dimitrioglo

1
@D. Dimitrioglo 모두 좋습니다. 소스 디렉토리 문제였습니다. 감사합니다 :)
— Jake

17

child_process이를 위해 Node의 네이티브 API를 사용하세요.

타사 라이브러리가 필요하지 않습니다. 두 줄의 코드.

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
});

동기식 API를 사용하고 있습니다. child_process.exec(path, options, callback)비동기가 필요한 경우 사용할 수 있습니다 . 요청을 더 세부적으로 조정하기 위해 CWD를 지정하는 것보다 훨씬 더 많은 옵션이 있습니다. exec / execSync 문서를 참조하십시오 .


참고 : 이 예제는 시스템에 zip 유틸리티가 설치되어 있다고 가정합니다 (적어도 OSX와 함께 제공됨). 일부 운영 체제에는 유틸리티가 설치되어 있지 않을 수 있습니다 (예 : AWS Lambda 런타임에는 설치되지 않음). 이 경우 여기 에서 쉽게 zip 유틸리티 바이너리를 가져 와서 애플리케이션 소스 코드와 함께 패키징하거나 (AWS Lambda의 경우 Lambda 계층에서도 패키징 할 수 있음) 타사 모듈을 사용해야합니다. (그 중 NPM에 많은 것이 있습니다). ZIP 유틸리티는 수십 년 동안 시도되고 테스트 되었기 때문에 이전 접근 방식을 선호합니다.


9
불행히도 zip.
— janpio 2019

3
내 프로젝트에서 수십 개의 외부 라이브러리를 피하기 위해이 솔루션을 사용했습니다
— EAzevedo

말이되지만 내가 틀리지 않다면 이것은 Windows 사용자를 다시 망친다. Windows 사용자를 생각하십시오!
— Mathijs Segers

트윗 담아 가기 그래서 Windows 사용자도 얻을 수 있도록 바이너리에 대한 링크를 포함 시켰습니다! :)
— Govind Rai

컴퓨터 디렉토리가 아닌 프로젝트 내의 디렉토리에서 작동하도록하는 방법이 있습니까?
— Matt Croak

13

Archive.bulk이제 더 이상 사용되지 않으며이를 위해 사용할 새 메서드는 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
이것에 대해 궁금해서, 그들은 대량이 더 이상 사용되지 않는다고 말했지만 대신 사용할 기능을 제안하지 않았습니다.
— jarodsmk

1
"소스"디렉토리를 어떻게 지정합니까?
— Dreams

접근 아래에 한 번보십시오 : jsonworld.wordpress.com/2019/09/07/...
— SONI 쿠마리에게

2020 : archive.directory ()가 훨씬 더 간단합니다!
— OhadR


9

이것은 폴더를 한 줄로 압축 하는 또 다른 라이브러리입니다. zip-local

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

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

4
나를 위해 인터넷에서 사용할 수있는 다른 사람의 다스와는 달리, 마법처럼 일했다거나하는 항상 '0 바이트'파일 생성, 위에서 언급 한
— 세르게이 Pleshakov

4

결과를 응답 개체로 파이프하려면 (로컬에 저장하지 않고 zip을 다운로드해야하는 시나리오)

 archive.pipe(res);

디렉토리의 내용에 액세스하기위한 Sam의 힌트가 저에게 효과적이었습니다.

src: ["**/*"]

3

Adm-zip에는 기존 아카이브 https://github.com/cthackers/adm-zip/issues/64 를 압축하는 데 문제가 있을뿐만 아니라 바이너리 파일 압축으로 인한 손상이 있습니다.

또한 node-zip https://github.com/daraosn/node-zip/issues/4에서 압축 손상 문제가 발생했습니다.

node-archiver는 압축에 잘 작동하는 유일한 것으로 보이지만 압축 해제 기능이 없습니다.


1
어떤 노드 아카이브에 대해 이야기하고 있습니까? : github.com/archiverjs/node-archiver; github.com/richardbolt/node-archiver
— biphobe

@firian 그는 Archiver라고 말하지 않았고 Adm-zip이라고 말했습니다.
— Francis Pelland

5
@FrancisPelland Umm, 마지막 문장에서 그는 " 노드 아카이브가 작동하는 것처럼 보이는 유일한 사람입니다 "라고 썼습니다 . 그게 제가 말하는 것입니다.
— biphobe

나는 그가 고기 npmjs.com/package/archiver
— OhadR


1

이후 archiver오랫동안 웹팩의 새 버전과 호환되지 않습니다, 내가 사용하는 것이 좋습니다 지퍼 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

간단한 방법으로 시도 할 수 있습니다.

설치 zip-dir:

npm install zip-dir

그리고 그것을 사용하십시오

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

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

    });

zip 폴더를 만들기 위해 매개 변수를 추가 할 수 있습니까? 압축 수준 및 크기와 같은 경우 어떻게해야합니까?
— Trang D

0

내 프로젝트를 통해 리팩토링하는 데 너무 많은 노력이 필요하기 때문에 JSZip을 에뮬레이트하기 위해 아카이버를 래핑했습니다. 나는 Archiver가 최선의 선택이 아닐 수도 있다는 것을 이해하지만 여기 있습니다.

// 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);
    }
};
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.