fs.writeFile(path, data, callback)은 문자열이나 Buffer를 파일에 씁니다. 파일이 없으면 Node.js가 만들고, 있으면 원래 내용을 교체합니다. fs.writeFileSync(path, data)는 같은 일을 쓰기가 끝날 때까지 기다리며 하고, fs.appendFile은 교체하지 않고 파일 끝에 덧붙입니다.
saved와 다시 읽은 텍스트가 출력됩니다. 콜백은 에러(또는 null)만 받고 데이터는 절대 받지 않습니다. 문자열 대신 42를 넘기면 호출이 TypeError를 던집니다. 데이터는 문자열이나 Buffer여야 합니다.
writeFile, writeFileSync, fs/promises
세 형태는 같은 인자를 받고, 결과를 기다리는 방법만 다릅니다.
const fs = require('fs');
const fsp = require('fs/promises');
fs.writeFileSync('a.txt', 'one'); // blocks, throws on error
fs.writeFile('b.txt', 'two', (err) => {}); // callback with err
await fsp.writeFile('c.txt', 'three'); // promise, use in async code
스크립트와 시작 코드에서는 writeFileSync를, 서버에서는 Promise 버전을 쓰세요. 서버에서 동기 쓰기를 하면 디스크 작업이 끝날 때까지 다른 모든 요청이 막힙니다. Promise API의 나머지는 fs/promises 페이지에 있습니다.
appendFile로 파일에 덧붙이기
writeFile은 파일 전체를 교체합니다. 로그에 한 줄을 추가하려면 appendFile을 쓰세요. 처음에는 파일도 만들어 줍니다.
첫 번째 읽기는 "second\n"을 출력합니다. 두 번째 writeFileSync가 first를 교체했기 때문입니다. 두 번째 읽기는 "second\nthird\nfourth\n"을 출력합니다(JSON.stringify로 줄바꿈이 보이게 했습니다). \n은 직접 붙이세요. 두 함수 모두 붙여 주지 않습니다.
writeFile | appendFile | |
|---|---|---|
| 파일이 없을 때 | 만듦 | 만듦 |
| 파일이 있을 때 | 내용을 교체 | 끝에 덧붙임 |
| 기본 플래그 | 'w' | 'a' |
| 주 용도 | 문서나 JSON 전체 저장 | 로그를 한 줄씩 |
덮어쓰지 않기: flag 옵션
세 번째 인자로 옵션 객체를 넘길 수 있습니다. 그 flag가 기존 파일을 어떻게 할지 정합니다. 'wx'는 "쓰되, 파일이 이미 있으면 실패"라는 뜻으로, 파일을 한 번만 만드는 안전한 방법입니다.
두 번째 호출은 EEXIST로 실패하므로 파일에는 여전히 abc123이 들어 있습니다. 두 번째 호출의 파일 이름을 id2.txt로 바꾸면 두 호출 모두 created를 출력합니다.
자주 만나는 플래그는 'w'(기본, 교체), 'a'(덧붙이기), 'wx'(새로 만들기만), 'ax'(덧붙이되 새 파일에만)입니다.
먼저 fs.existsSync로 확인하고 나서 쓰는 방식에는 틈이 있습니다. 확인과 쓰기 사이에 다른 프로세스가 파일을 만들 수 있기 때문입니다. 'wx'는 둘을 한 단계로 합니다.
JSON을 파일로 쓰기
writeFile은 객체를 받지 않습니다. JSON.stringify로 텍스트로 바꾸세요. 세 번째 인자 2는 출력을 들여 써서 파일을 읽기 좋게 만듭니다.
파일에는 객체가 들여쓰기된 여러 줄로 들어가고, 다시 파싱하면 같은 객체가 되므로 마지막 줄은 2를 출력합니다. JSON.stringify 없이 객체를 넘기면 호출이 TypeError를 던집니다.
mkdir로 폴더 먼저 만들기
writeFile은 파일을 만들지 폴더는 만들지 않습니다. reports가 없을 때 reports/2026/june.txt에 쓰면 ENOENT로 실패합니다. 먼저 mkdir와 { recursive: true }로 경로를 만드세요. 없는 폴더를 모두 만들고, 이미 있으면 아무것도 하지 않습니다.
첫 쓰기는 ENOENT로 실패하고, mkdir 뒤에는 같은 쓰기가 성공해 readdir이 [ 'june.txt' ]를 나열합니다. 실제 코드에서는 윈도우에서도 동작하도록 이런 경로를 path.join으로 만드세요.
흔한 실수
호출 직후에 파일이 써졌다고 가정하는 것. fs.writeFile은 데이터가 디스크에 닿기 전에 반환합니다. 파일을 읽거나 다음 단계를 시작하는 일은 콜백 안에서 하거나, Promise 버전을 await하세요.
반복문 안에서 써서 데이터를 잃는 것. 항목마다 writeFile을 호출하면 매번 파일이 교체되어 마지막 항목만 남습니다. appendFile을 쓰거나, 문자열 전체를 만든 뒤 한 번에 쓰세요.
[object Object]를 쓰는 것. 객체를 String()이나 템플릿 리터럴에 넣으면 [object Object]가 써집니다. JSON.stringify를 쓰세요.
자주 묻는 질문
fs.writeFile은 파일을 덮어쓰나요?
네. 기본 플래그 'w'는 파일을 비운 뒤 새 데이터를 쓰므로 원래 내용은 사라집니다. 끝에 덧붙이려면 { flag: 'a' }를 넘기거나 appendFile을 쓰세요.
fs.writeFile은 없는 파일을 만들어 주나요?
네, 파일은 만듭니다. 하지만 없는 폴더는 만들지 않습니다. logs가 없을 때 logs/app.log에 쓰면 ENOENT로 실패합니다.
데이터로 무엇을 넘길 수 있나요?
문자열, Buffer, 타입 배열입니다. 객체나 숫자처럼 그 밖의 것은 TypeError를 던지므로, 객체는 JSON.stringify로, 숫자는 String()으로 먼저 바꾸세요.
같은 파일에 writeFile을 동시에 여러 번 호출해도 안전한가요?
아닙니다. 한 파일에 writeFile 두 개를 병렬로 호출하면 쓰기가 섞여 내용이 뒤죽박죽될 수 있습니다. 하나가 끝나길 기다렸다가 다음을 시작하거나, 데이터를 모아 한 번에 쓰세요.