파일복사
NodeJS는 기본적인 파일 작업 API를 제공하지만 파일 복사 등의 고급 기능은 제공하지 않으므로 먼저 파일 복사 프로그램으로 실습해 보겠습니다. 복사 명령과 마찬가지로 프로그램은 소스 파일 경로와 대상 파일 경로라는 두 가지 매개변수를 허용할 수 있어야 합니다.
소용량 파일 복사
NodeJS에 내장된 fs 모듈을 이용하여 이 프로그램을 간단하게 구현해 보면 다음과 같습니다.
var fs = require('fs'); function copy(src, dst) { fs.writeFileSync(dst, fs.readFileSync(src)); } function main(argv) { copy(argv[0], argv[1]); } main(process.argv.slice(2));
위 프로그램은 fs.readFileSync를 사용하여 소스 경로에서 파일 내용을 읽고, fs.writeFileSync를 사용하여 파일 내용을 대상 경로에 씁니다.
Bean 지식: process는 전역 변수이며 명령줄 매개변수는 process.argv를 통해 얻을 수 있습니다. argv[0]은 NodeJS 실행 프로그램의 절대 경로와 동일하고 argv[1]은 기본 모듈의 절대 경로와 동일하므로 첫 번째 명령줄 매개 변수는 argv[2] 위치에서 시작됩니다.
대용량 파일 복사
위 프로그램은 일부 작은 파일을 복사하는 데는 문제가 없지만 모든 파일 내용을 한 번에 메모리로 읽어 들인 다음 디스크에 한꺼번에 쓰는 이 방법은 대용량 파일을 복사하는 데 적합하지 않으며 메모리가 지쳐. 대용량 파일의 경우 복사가 완료될 때까지 조금만 읽고 조금만 쓸 수 있습니다. 따라서 위의 프로그램은 다음과 같이 수정될 필요가 있다.
var fs = require('fs'); function copy(src, dst) { fs.createReadStream(src).pipe(fs.createWriteStream(dst)); } function main(argv) { copy(argv[0], argv[1]); } main(process.argv.slice(2));
위 프로그램은 fs.createReadStream을 사용하여 소스 파일에 대한 읽기 전용 데이터 스트림을 생성하고 fs.createWriteStream을 사용하여 대상 파일에 대한 쓰기 전용 데이터 스트림을 생성한 후 파이프 메서드를 사용하여 두 파일을 연결합니다. 데이터 스트림. 연결이 이루어진 후에 일어나는 일은 더 추상적으로 말하면 물이 파이프를 따라 한 양동이에서 다른 양동이로 흐른다는 것입니다.
디렉토리 탐색
파일을 조작할 때 디렉터리 순회는 일반적인 요구 사항입니다. 예를 들어 지정된 디렉터리에서 모든 JS 파일을 찾아 처리해야 하는 프로그램을 작성하는 경우 전체 디렉터리를 탐색해야 합니다.
재귀 알고리즘
재귀 알고리즘은 일반적으로 디렉토리를 순회할 때 사용됩니다. 그렇지 않으면 간결한 코드를 작성하기가 어렵습니다. 재귀 알고리즘은 문제의 크기를 지속적으로 줄여 문제를 해결한다는 점에서 수학적 귀납법과 유사합니다. 다음 예에서는 이 접근 방식을 보여줍니다.
function factorial(n) { if (n === 1) { return 1; } else { return n * factorial(n - 1); } }
위 함수는 N(N!)의 계승을 계산하는 데 사용됩니다. 보시다시피, N이 1보다 크면 문제는 N 곱하기 N-1의 계승을 계산하는 것으로 줄어듭니다. N이 1이면 문제가 최소 크기에 도달하고 더 이상의 단순화가 필요하지 않으므로 1이 직접 반환됩니다.
트랩: 재귀 알고리즘을 사용하여 작성한 코드는 간단하지만 각 재귀마다 함수 호출이 발생하므로 성능을 우선시해야 하는 경우에는 재귀 알고리즘을 루프 알고리즘으로 변환하여 함수 호출 횟수를 줄여야 합니다.
순회 알고리즘
디렉토리는 트리 구조로 되어 있으며, 순회할 때 일반적으로 깊이 우선 + 선주문 순회 알고리즘을 사용합니다. 깊이 우선이란 노드에 도달한 후 이웃 노드 대신 하위 노드를 먼저 통과하는 것을 의미합니다. 선주문 순회는 마지막으로 노드로 돌아올 때가 아니라 처음으로 노드에 도달할 때 순회가 완료됨을 의미합니다. 따라서 이 순회 방법을 사용하는 경우 아래 트리의 순회 순서는 A > B > D > C > F입니다.
A / \ B C / \ \ D E F
동기 순회
필요한 알고리즘을 이해한 후에는 다음 디렉터리 탐색 기능을 간단히 구현할 수 있습니다.
function travel(dir, callback) { fs.readdirSync(dir).forEach(function (file) { var pathname = path.join(dir, file); if (fs.statSync(pathname).isDirectory()) { travel(pathname, callback); } else { callback(pathname); } }); }
보시다시피 이 함수는 디렉토리를 순회 시작점으로 사용합니다. 하위 디렉터리를 만나면 해당 하위 디렉터리를 먼저 탐색합니다. 파일이 발견되면 파일의 절대 경로가 콜백 함수에 전달됩니다. 콜백 함수는 파일 경로를 얻은 후 다양한 판단과 처리를 할 수 있습니다. 그럼 다음 디렉터리가 있다고 가정해 보겠습니다.
- /home/user/ - foo/ x.js - bar/ y.js z.css
다음 코드를 사용하여 디렉터리를 순회할 때 얻은 입력은 다음과 같습니다.
travel('/home/user', function (pathname) { console.log(pathname); });
/home/user/foo/x.js /home/user/bar/y.js /home/user/z.css
비동기 순회
디렉토리를 읽거나 파일 상태를 읽을 때 비동기 API를 사용하면 디렉터리 순회 기능을 구현하기가 조금 복잡해지지만 원리는 완전히 동일합니다. 여행 기능의 비동기 버전은 다음과 같습니다.
function travel(dir, callback, finish) { fs.readdir(dir, function (err, files) { (function next(i) { if (i < files.length) { var pathname = path.join(dir, files[i]); fs.stat(pathname, function (err, stats) { if (stats.isDirectory()) { travel(pathname, callback, function () { next(i + 1); }); } else { callback(pathname, function () { next(i + 1); }); } }); } else { finish && finish(); } }(0)); }); }
비동기 순회 함수의 작성 기술은 여기서 자세히 소개하지 않습니다. 이에 대해서는 다음 장에서 자세히 소개하겠습니다. 간단히 말해서, 비동기 프로그래밍이 상당히 복잡하다는 것을 알 수 있습니다.