[2026] Node.js File System: Complete Guide to the fs Module
이 글의 핵심
Node.js fs module guide: sync vs async APIs, fs.promises, read/write JSON, directories, streams, watch, chokidar, errors, and performance—essential for Express and CLI tools.
Introduction
What is the fs module?
fs is Node’s built-in API for files and directories. Capabilities:
- Read/write files
- Create/remove directories
statmetadata- Watch for changes
- Stream large data
Three styles: synchronous (
*Sync), callback, and Promise (fs.promises) — prefer Promises withasync/awaitfor server code.
1. Reading files
Synchronous (blocking)
아래 코드는 javascript를 사용한 구현 예제입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
const fs = require('fs');
try {
const data = fs.readFileSync('file.txt', 'utf8');
console.log(data);
} catch (err) {
console.error(err.message);
}
Avoid on request handlers—it blocks the event loop.
Callback
다음은 간단한 javascript 코드 예제입니다. 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) return console.error(err.message);
console.log(data);
});
Promises (recommended)
아래 코드는 javascript를 사용한 구현 예제입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
const fs = require('fs').promises;
async function readFile() {
try {
const data = await fs.readFile('file.txt', 'utf8');
console.log(data);
} catch (err) {
if (err.code === 'ENOENT') console.error('Missing file');
else if (err.code === 'EACCES') console.error('Permission denied');
else console.error(err.message);
}
}
readFile();
Encoding and buffers
다음은 간단한 javascript 코드 예제입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
const text = await fs.readFile('text.txt', 'utf8');
const buf = await fs.readFile('image.png'); // Buffer
const asString = buf.toString('utf8');
const base64 = buf.toString('base64');
2. Writing files
const fs = require('fs').promises;
await fs.writeFile('out.txt', 'Hello, Node.js!', 'utf8');
await fs.appendFile('out.txt', '\nMore', 'utf8');
JSON helpers
아래 코드는 javascript를 사용한 구현 예제입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
async function readJSON(file) {
try {
const data = await fs.readFile(file, 'utf8');
return JSON.parse(data);
} catch (err) {
if (err.code === 'ENOENT') return null;
throw err;
}
}
async function writeJSON(file, obj) {
await fs.writeFile(file, JSON.stringify(obj, null, 2), 'utf8');
}
3. File metadata and operations
아래 코드는 javascript를 사용한 구현 예제입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
const stats = await fs.stat('file.txt');
console.log(stats.size, stats.isFile(), stats.isDirectory());
await fs.copyFile('a.txt', 'b.txt');
await fs.rename('b.txt', 'c.txt');
await fs.unlink('c.txt');
await fs.chmod('file.txt', 0o755); // Unix
Existence check
아래 코드는 javascript를 사용한 구현 예제입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
async function exists(file) {
try {
await fs.access(file);
return true;
} catch {
return false;
}
}
4. Directories
아래 코드는 javascript를 사용한 구현 예제입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
await fs.mkdir('nested/path', { recursive: true });
const names = await fs.readdir('.');
const entries = await fs.readdir('.', { withFileTypes: true });
await fs.rm('dir', { recursive: true, force: true });
Recursive directory walk and findJSFiles patterns follow the idioms below.
5. Streams
See async & streams post for createReadStream, pipe, zlib, and Transform—the same patterns apply here.
6. Watching files
fs.watch
const watcher = fs.watch('dir', { recursive: true }, (event, filename) => {
console.log(event, filename);
});
chokidar
npm install chokidar
const chokidar = require('chokidar');
chokidar.watch('src/**/*.js').on('change', (path) => console.log('changed', path));
7. Practical examples
JSON read/write (full flow)
다음은 javascript를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
const fs = require('fs').promises;
async function readJSON(filename) {
try {
const data = await fs.readFile(filename, 'utf8');
return JSON.parse(data);
} catch (err) {
if (err.code === 'ENOENT') return null;
throw err;
}
}
async function writeJSON(filename, data) {
await fs.writeFile(filename, JSON.stringify(data, null, 2), 'utf8');
}
async function main() {
const users = [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 }
];
await writeJSON('users.json', users);
const loaded = await readJSON('users.json');
loaded[0].age = 26;
await writeJSON('users.json', loaded);
}
main().catch(console.error);
Recursive directory walk
다음은 javascript를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
const fs = require('fs').promises;
const path = require('path');
async function walk(directory, onFile) {
const entries = await fs.readdir(directory, { withFileTypes: true });
for (const entry of entries) {
const full = path.join(directory, entry.name);
if (entry.isDirectory()) await walk(full, onFile);
else await onFile(full);
}
}
async function findJsFiles(root) {
const out = [];
await walk(root, async (file) => {
if (path.extname(file) === '.js') out.push(file);
});
return out;
}
Backup helper (simplified)
다음은 javascript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 비동기 처리를 통해 효율적으로 작업을 수행합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
class BackupManager {
constructor(sourceDir, backupDir) {
this.sourceDir = sourceDir;
this.backupDir = backupDir;
}
async backup() {
const fs = require('fs').promises;
const path = require('path');
await fs.mkdir(this.backupDir, { recursive: true });
const stamp = new Date().toISOString().replace(/:/g, '-');
const destDir = path.join(this.backupDir, `backup-${stamp}`);
await fs.mkdir(destDir);
const files = await fs.readdir(this.sourceDir);
for (const name of files) {
const src = path.join(this.sourceDir, name);
const stat = await fs.stat(src);
if (stat.isFile()) {
await fs.copyFile(src, path.join(destDir, name));
}
}
return destDir;
}
}
CSV via readline (sketch)
다음은 javascript를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
const fs = require('fs');
const readline = require('readline');
async function parseCsv(filename) {
const stream = fs.createReadStream(filename);
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
const rows = [];
let headers = [];
let first = true;
for await (const line of rl) {
if (first) {
headers = line.split(',');
first = false;
continue;
}
const cols = line.split(',');
const obj = {};
headers.forEach((h, i) => {
obj[h.trim()] = (cols[i] || ').trim();
});
rows.push(obj);
}
return rows;
}
8. Error codes
Handle ENOENT, EACCES, EISDIR, ENOTDIR, EEXIST as in the original tables.
Safe write pattern (write temp then rename)
Atomic-ish replace by writing to file.tmp then fs.rename to final path—see the safeFileOperation helper pattern below.
9. Performance
- Tune
highWaterMarkon streams - Prefer
Promise.allfor independent reads - Stream line counts instead of loading multi-GB files fully
10. Common pitfalls
- Use
path.join(__dirname, 'file.txt')instead of fragile relative paths - Pass
'utf8'when you expect a string - Avoid
readFileSyncin Express handlers - Close streams or use
stream.pipeline/util.promisify(pipeline)
Summary
| Style | Server use | CLI / boot |
|---|---|---|
| Sync | Avoid | OK |
| Callback | Legacy | OK |
fs.promises | Preferred | Preferred |