본문으로 바로가기
  1. 모듈 이용 연습 (fs 및 crypto)
  2. 콜백 함수 연습
  3. Object, Exception 처리 등 기타 연습

자바스크립트 및 Node.js/Node.js 모듈 연습용 코드입니다.

중복 파일을 SHA-256 해시값을 이용해 검사한 후 해당 파일을 '중복파일'이란 이름의 폴더에 저장하는 코드입니다.

 

 

코드

const fs = require('fs');
const crypto = require('crypto');
let files = {
    path: process.argv[2],
    list: []
}
let timetable = new Array();


const getFileList = function(path, callback) {
    fs.readdir(path, function(err, list) {
        if(!err) callback(list.slice());
        else throw err;
    });
}

const getFileHash = function(filePath, fileName, callback) {
    fs.lstat(`${filePath}/${fileName}`, function(err, stats) {
        if(!err && stats.isFile()) {
            let input =  fs.createReadStream(`${filePath}/${fileName}`);
            let hash = crypto.createHash('sha256');
            input.on('readable', function() {
                let data = input.read(); //데이터가 있으면 다시 이벤트 루프로
                if (data) hash.update(data);
                else callback(hash.digest('hex'));
            });
        } else if(!err && !stats.isFile()) callback(null);
        else callback(err);
    });
}

let now = 0;
const addHashValue = function(filePath, fileList, callback) {
    getFileHash(filePath, fileList[now], function(hash) {
        //console.log(`${now} : ${fileList[now]} : ${hash}`);
        if(now<fileList.length) {
            files.list[now] = {
                key: now,
                name: fileList[now],
                hash: hash
            };
            now++;
            addHashValue(filePath, fileList, callback);
        } else callback(true);
    });
}

const checkDuplicateData = function(callback) {
    files.list.forEach((v1, i1) => {
        if(files.list[i1].duplicate == null) {
            files.list.forEach((v2, i2) => {
                if(i1 != i2 && files.list[i1].hash != null && files.list[i1].hash == files.list[i2].hash) files.list[i2].duplicate = i1;
                if(i1==files.list.length-1 && i2==files.list.length-1) callback(); // 마지막인지 검사
            })
        }
    })
}

const moveDuplicateData = function(path, callback) {
    files.list.forEach((v, i) => {
        if(v.duplicate != null) {
            fs.rename(`${path}/${v.name}`, `${path}/중복파일/${v.name}`, function(err) {
                if(!err) console.log(`${v.name} 파일이 이동되었습니다.`)
                if(err) console.log(`${v.name} 파일 이동에 실패하였습니다.`);
            });
        }
    });
}



getFileList(files.path, function(fileList) {
    fs.mkdir(`${files.path}/중복파일`, (err) => {
        if(err && err.code=='EEXIST') console.log("중복파일 저장폴더가 이미 존재합니다.");
        else if (err && err.code!='EEXIST') throw 'up';
        else console.log("중복파일 저장폴더가 생성되었습니다.")
    });
    addHashValue(files.path, fileList, () => {
        checkDuplicateData(() => {
            //console.log(files.list);
            moveDuplicateData(files.path, (e) => {
                if(e) console.log("중복파일 이동이 완료되었습니다.")
                else console.log("중복파일 이동이 실패하였습니다.")
            })
        })
    });
});

 

 

 

실행 결과

PS C:\Users\LETRO\Documents\Workspace\Nodejs> node .\중복파일검색.js "./"
중복파일 저장폴더가 생성되었습니다.
compareHash copy.js 파일이 이동되었습니다.
compareHash.js 파일이 이동되었습니다.
test copy.js 파일이 이동되었습니다.
test.js 파일이 이동되었습니다.
PS C:\Users\LETRO\Documents\Workspace\Nodejs> 

 

문제점

  1. 남아있는 파일이 원본 파일임을 보증하지 않는다.
  2. 파일이 1000개가 넘으면 많이 느리다.