fs 모듈 — 파일 읽기·쓰기, 동기 vs 비동기
브라우저가 막아둔 영역. Node 가 가장 빛나는 도구 fs 를 손에 익히자.
드디어 Node 의 진짜 무대 — 파일 시스템. 브라우저 자바스크립트는 보안 때문에 파일에 접근 못 한다. Node 는 막힘이 없다. 그래서 자동화 스크립트·정적 사이트 빌더·CLI 도구가 다 Node 로 만들어졌다.
관문은 fs 모듈 한 가지. 이 모듈은 같은 동작에 대해 3가지 API 를 제공한다. 동기·비동기 콜백·Promise. 어느 걸 골라야 하는지 헷갈리니, 이번 편에서 정리.
1. 3가지 API — 같은 동작 세 가지 모양
같은 "파일 읽기" 동작이 세 가지 형태로 존재한다.
결과는 셋 다 같지만 — 이벤트 루프를 어떻게 다루느냐가 다르다. 그래서 어떤 API 를 쓰는가가 서버 성능을 좌우한다.
| API | 패키지 | 동작 | 권장 |
|---|---|---|---|
| 동기 | node:fs 의 ...Sync | 호출 즉시 막힘. 끝날 때까지 다른 일 X | 스크립트·CLI 시작·설정 읽기 |
| 콜백 | node:fs (Sync 없는 함수) | 백그라운드 시작 + 끝나면 콜백 호출 | 레거시. 신규는 비추 |
| Promise | node:fs/promises | await 로 받음. 콜백과 같은 비동기 | 기본. 모든 신규 코드 |
2. 가장 많이 쓰는 메서드 6가지
실전에서 99% 를 차지하는 함수 6개. node:fs/promises 기반으로 보면 된다.
모든 함수는 실패하면 throw. try/catch 또는 .catch() 로 감싸자. 콜백 API 의 (err, data) => … 형태는 옛날 방식.
readFile 두 번째 인자가 인코딩. 'utf-8' 주면 문자열, 안 주면 Buffer (바이너리). 이미지·PDF 같은 바이너리는 인코딩 없이 받아 그대로 다른 함수에 전달.
3. 동기 API 는 언제 쓰나 — 두 가지 케이스만
비동기가 기본이지만, 동기 (...Sync) 가 옳은 경우 두 가지.
① 프로세스 시작 시 설정 읽기
서버가 일을 시작하기 전에 필요한 설정. 어차피 이게 끝나야 다음이 의미가 있다.
여기서 비동기를 쓰면 코드 흐름만 복잡해지고 얻는 게 없다. 어차피 서버는 설정 없이 시작 못 함.
② 짧은 CLI 스크립트
한 번 돌고 끝나는 자동화 스크립트. 동시 요청이 없으므로 막혀도 손해 없음.
이런 1회성 스크립트는 동기가 읽기 쉬워서 더 낫다. await 줄줄이 나열할 필요 없음.
4. 서버에선 절대 동기를 쓰지 마라
가장 큰 함정. HTTP 서버의 요청 핸들러 안에서 readFileSync 를 호출하면 어떤 일이?
readFileSync 가 10ms 걸리면 그 10ms 동안 다른 모든 요청이 멈춘다. 1000 RPS 부하라면 누적 지연이 폭발한다. 옛 Pages Router 시절 getServerSideProps 안에 동기 fs 박은 사례가 가장 흔한 사고. 이래서 비동기가 기본인 것.
서버 코드에선 무조건 node:fs/promises 의 await 형태. 의식하지 않아도 되도록 처음부터 fs/promises 만 import 하는 습관을 들이자.
5. 흔한 패턴 — 존재 확인 + 안전한 쓰기
실전에서 자주 만나는 두 패턴.
존재하면 읽고 없으면 생성
e.code === 'ENOENT' 가 "파일 없음" 의 표준 에러 코드. fs.exists 같은 별도 함수 쓰지 말고 try/catch 패턴이 표준이다 (exists 는 race condition 이 있어 deprecated).
임시 파일 → 본 파일 교체 (원자적 쓰기)
쓰기 도중 프로세스가 죽어도 원본은 안전. 데이터 저장이 중요한 경우 표준 패턴.
요약 — 6편 좌표
여기까지 정리. fs 는 3가지 API — 동기(...Sync) · 콜백 · Promise. 현재 표준은 node:fs/promises + await. 동기는 프로세스 시작 설정과 1회성 스크립트에만, 서버 핸들러엔 절대 금지. 자주 쓰는 메서드는 readFile·writeFile·appendFile·stat·mkdir·readdir 6개. 존재 확인은 try/catch + ENOENT 패턴, 중요 데이터는 임시 파일 → rename 원자적 쓰기. 다음 편에선 path 와 os 모듈로 경로 다루기.
다음 편 예고 — path와 os 모듈
크로스 플랫폼 경로 다루기와 시스템 정보 읽기. 7편.