raytency’s diary

画像とテーブルはそのうち上げます

Node.jsで複数フォルダをzipで圧縮

この記事は

Node.jsにて

  • archiverを使ったzip圧縮
  • child_processを使ったマルチスレッド化

したソースコードが乗っかっているだけ

やりたいこと

HDDのデータを整理するのに、フォルダ毎に圧縮して保存したいな~という需要があった。  

Folder
├Folder1
│├file1
│└file2
├Folder2
│├file1
│└file2
├Folder3
│├file1
│└file2
・・・

これを

Folder
├Folder1.zip
├Folder2.zip
├Folder3.zip
・・・

という具合にしたい。 7zipとバッチファイルでなんとかする試みもある。 これはD&Dで圧縮出来てとても便利なので、これを使えばいいと思うが今回はnodejsで作ってみた。

child_processを使ったので、親子で2ファイルある。

  • 親:フォルダのリストを作って、子に渡す
  • 子:与えられたフォルダの中身をアーカイブ

使うときはmain.jsとchild.jsを同じ階層に入れてmain.jsを実行

folder
├main.js
└child.js

親側 main.js

const fs = require('fs')
const child_process = require('child_process')

// 対象フォルダ
const sourceDir = "/home/raytency/data/"
// プロセス数
const cpuNum = 8

// フォルダのリスト
let folders = []

function createProc(){
    // リストから一つ取り出し
    let folder = folders[0]
    let filepath = sourceDir+"\\"+folder
    folders.shift()
    // プロセス生成
    cproc = child_process.fork("./child",null,{env:{filepath:filepath}})
    cproc.on("exit",()=>{
        // 子プロセス終了時、リストが残ってたらまた新たにプロセス生成
        if(folders.length>0){
            createProc()
        } else { 
            console.log("exit....")
        }
    })
}

function main(){
    // 対象フォルダ内にあるフォルダのリストを作成
    let allFiles = fs.readdirSync(sourceDir)
    folders = allFiles.filter((file)=>{
        return fs.statSync(sourceDir+"\\"+file).isDirectory()
    })
    // コア数ぶん子プロセス立ち上げ
    for(let i=0; i<cpuNum; i++){
        createProc()
    }
}

main()

子側 child.js

const archiver = require('archiver')
const fs = require('fs')
const path = require('path')

// source: アーカイブ化したいフォルダのパス
// dest: 生成したいzipファイルのパス
function zipFolder(source, dest){
    var archive = archiver.create( 'zip', {zlib: { level: 5 }} )

    var output = fs.createWriteStream( dest );

    output.on('close', function() {
        console.log(archive.pointer() + ' total bytes');
    });

    archive.pipe(output)

    //ファイルをどんどんついかする
    let allFiles = fs.readdirSync(source)

    for(file of allFiles){
        //console.log("[file Name] "+file);
        let stat = fs.statSync(source+"\\"+file)
        if(stat.isFile()){
            archive.file(source+"\\"+file,{name: file})
        }
        if(stat.isDirectory()){
            archive.directory(source+"\\"+file, file)
        }
    }

    archive.finalize();
}

let dest = process.env.filepath + ".zip"
zipFolder(process.env.filepath, dest)
console.log(path.basename(process.env.filepath))