-
노드 파일 시스템 사용하기노드 2023. 4. 12. 14:00
fs
파일 시스템에 접근하는 모듈이다.
- 파일/폴더 생성, 삭제, 일기, 쓰기 가능
- 웹 브라우저에서는 제한적이었으나 노드는 권한을 가지고 있다.
readme라는 파일을 읽는 방법은 다음과 같다
//readFile.js const fs = require('fs'); fs.readFile('./readme.txt', (err, data) => { if (err) { throw err; } console.log(data); console.log(data.toString()); });
콘솔에 data를 출력하면 바이너리 데이터(여기서는 2진법을 16진법으로 변환되서 받아온다)로 받아오는 것을 확인 할 수 있다.
fs를 프로미스화 하려면 전에 설명했던 util.promisify를 쓰는 방법도 있지만 fs는 더 좋은 방법을 제공한다.
//readFile.js const fs = require('fs').promises; fs.readFile('./readme.txt') .then((data) => { console.log(data); console.log(data.toString()); }) .catch((err) => { throw err; });
promises를 사용하여 변환한 모습이다.
다음은 파일을 쓰는 방법이다.
//writeFile.js const fs = require('fs'); fs.writeFile('./writeme.txt', '철권 8', (err) => { if (err) { throw err; } fs.readFile('./writeme.txt', (err, data) => { if (err) { throw err; } console.log(data.toString()); }); });
이것도 promises를 사용한다면 다음과 같다
//writeFile.js const fs = require('fs').promises; fs.writeFile('./writeme.txt', '철권 8') .then(() => { return fs.readFile('./writeme.txt'); }) .then((data) => { console.log(data.toString()); }) .catch(() => { throw err; });
실행한다면 writeFile.txt 파일이 생성되고 동시에 철권 8 이라는 문구도 써지는 것을 확인 할 수 있다.
fs.readFile 등등은 비동기 함수이다. 때문에 순서에 주의할 필요가 있다.
//async.js const fs = require('fs'); console.log('시작'); fs.readFile('./readme2.txt', (err, data) => { if (err) { throw err; } console.log('1번', data.toString()); }); fs.readFile('./readme2.txt', (err, data) => { if (err) { throw err; } console.log('2번', data.toString()); }); fs.readFile('./readme2.txt', (err, data) => { if (err) { throw err; } console.log('3번', data.toString()); }); console.log('끝');
비동기 함수들은 백그라운드로 먼저 보내지게 되고 그 사이에 동기 함수들은 먼저 실행되게 된다. 따라서 시작, 끝이 먼저 출력된 것이다.
백그라운드로 이동된 함수들은 동시에 실행된다. 단, 어떤 함수가 먼저 출력 될지는 운영체제 밖에 모른다.
따라서 결과가 이렇게 뒤죽박죽인 것을 확인 할 수 있다.
순서에 맞게 실행하려면?
동기 메서드와 비동기 메서드
- 동기와 비동기 : 백그라운드 작업 완료 확인 여부
*비동기를 유지한채로 순서대로 실행 또는 비동기 함수를 동기식으로 실행하는 방법 두 가지가 있다.
- 블로킹과 논 블로킹 : 함수가 바로 return 되는지 여부
- 노드에서는 대부분 동기 - 블로킹 방식과 비동기 - 논 블로킹 방식을 쓴다.
동기 메서드 사용하기
//sync.js const fs = require('fs'); console.log('시작'); let data = fs.readFileSync('./readme2.txt'); console.log('1번', data.toString()); data = fs.readFileSync('./readme2.txt'); console.log('2번', data.toString()); data = fs.readFileSync('./readme2.txt'); console.log('3번', data.toString()); console.log('끝');
fs는 동기함수도 지원한다.
당연히 순서대로 출력되는 것을 확인할 수 있다. 하지만 효율을 생각한다면 매우 좋지 않다.
따라서 비동기식으로 작업하고 순서를 유지하는 방식이 더 좋다.
//asyncOrder.js const fs = require('fs'); console.log('시작'); fs.readFile('./readme2.txt', (err, data) => { if (err) { throw err; } console.log('1번', data.toString()); fs.readFile('./readme2.txt', (err, data) => { if (err) { throw err; } console.log('2번', data.toString()); fs.readFile('./readme2.txt', (err, data) => { if (err) { throw err; } console.log('3번', data.toString()); console.log('끝'); }); }); });
함수 안에 또 다른 콜백 함수를 호출하는 식으로 순서를 유지했다. 동기 함수와는 달리 asyncOrder는 모두 백그라운드로 넘어가서 한꺼번에 실행되지만 순서를 지키면서 실행된다.
다만 이런식으로 하면 콜백 헬이 발생하는 것을 볼 수 있는데...
//asyncOrderPromise.js const fs = require('fs').promises; console.log('시작'); fs.readFile('./readme2.txt') .then((data) => { console.log('1번', data.toString()); return fs.readFile('./readme2.txt'); }) .then((data) => { console.log('2번', data.toString()); return fs.readFile('./readme2.txt'); }) .then((data) => { console.log('3번', data.toString()); console.log('끝'); }) .catch((err) => { console.error(err); });
promises를 써서 좀 더 깔끔하게 만들 수 있다. 더 깔끔하게 만들고 싶다면?
//asyncOderPromise.js const fs = require('fs').promises; async function main() { console.log('시작'); let data = await fs.readFile('./readme2.txt'); console.log('1번', data.toString()); data = await fs.readFile('./readme2.txt'); console.log('2번', data.toString()); data = await fs.readFile('./readme2.txt'); console.log('3번', data.toString()); data = await fs.readFile('./readme2.txt'); console.log('끝'); } main();
출력문은 위와 같고 이런 방법들이 동시성도 살리고 순서도 지키는 좋은 방법이다.
'노드' 카테고리의 다른 글
노드 pipe와 스트림 메모리 효율 확인 (0) 2023.04.12 노드 버퍼와 스트림 이해하기 (1) 2023.04.12 노드 child_process (0) 2023.04.12 노드 worker_threads (0) 2023.04.12 노드 crypto 와 util (0) 2023.04.12