728x90
반응형
1. fs 모듈 소개
Node.js의 fs(File System) 모듈은 파일 시스템과 상호작용하기 위한 API를 제공합니다. 동기(Sync), 콜백, Promise 세 가지 방식으로 파일 작업을 수행할 수 있습니다.
// 세 가지 API 스타일
const fs = require('fs'); // 콜백 기반
const fsSync = require('fs'); // 동기 (같은 모듈, Sync 접미사 메서드)
const fsPromises = require('fs').promises; // Promise 기반
// 또는
const { readFile, writeFile } = require('fs/promises');
2. 파일 읽기
2.1 비동기 읽기 (콜백)
const fs = require('fs');
// 텍스트 파일 읽기
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error('파일 읽기 오류:', err);
return;
}
console.log(data);
});
// 인코딩 없이 읽기 (Buffer 반환)
fs.readFile('image.png', (err, data) => {
if (err) throw err;
console.log(data); // <Buffer ...>
});
2.2 동기 읽기
const fs = require('fs');
try {
const data = fs.readFileSync('example.txt', 'utf8');
console.log(data);
} catch (err) {
console.error('파일 읽기 오류:', err);
}
2.3 Promise 기반 읽기
const fs = require('fs').promises;
async function readFileAsync() {
try {
const data = await fs.readFile('example.txt', 'utf8');
console.log(data);
} catch (err) {
console.error('파일 읽기 오류:', err);
}
}
readFileAsync();
2.4 다양한 읽기 옵션
const fs = require('fs').promises;
// 옵션 객체 사용
const data = await fs.readFile('example.txt', {
encoding: 'utf8',
flag: 'r' // 읽기 모드 (기본값)
});
// 주요 flag 값
// 'r' - 읽기, 파일 없으면 오류
// 'r+' - 읽기/쓰기, 파일 없으면 오류
// 'w' - 쓰기, 파일 없으면 생성, 있으면 덮어쓰기
// 'w+' - 읽기/쓰기, 파일 없으면 생성
// 'a' - 추가, 파일 없으면 생성
// 'a+' - 읽기/추가, 파일 없으면 생성
3. 파일 쓰기
3.1 비동기 쓰기 (콜백)
const fs = require('fs');
const content = 'Hello, Node.js!';
fs.writeFile('output.txt', content, 'utf8', (err) => {
if (err) {
console.error('파일 쓰기 오류:', err);
return;
}
console.log('파일이 저장되었습니다.');
});
3.2 동기 쓰기
const fs = require('fs');
try {
fs.writeFileSync('output.txt', 'Hello, Node.js!', 'utf8');
console.log('파일이 저장되었습니다.');
} catch (err) {
console.error('파일 쓰기 오류:', err);
}
3.3 Promise 기반 쓰기
const fs = require('fs').promises;
async function writeFileAsync() {
try {
await fs.writeFile('output.txt', 'Hello, Node.js!', 'utf8');
console.log('파일이 저장되었습니다.');
} catch (err) {
console.error('파일 쓰기 오류:', err);
}
}
writeFileAsync();
3.4 다양한 쓰기 옵션
const fs = require('fs').promises;
// 옵션 객체 사용
await fs.writeFile('output.txt', 'Hello', {
encoding: 'utf8',
mode: 0o644, // 파일 권한
flag: 'w' // 쓰기 모드
});
// JSON 파일 저장
const data = { name: '홍길동', age: 30 };
await fs.writeFile('data.json', JSON.stringify(data, null, 2), 'utf8');
반응형
4. 파일 추가 (Append)
4.1 appendFile 사용
const fs = require('fs').promises;
// 파일 끝에 내용 추가
await fs.appendFile('log.txt', '새로운 로그 항목\n', 'utf8');
// 콜백 방식
fs.appendFile('log.txt', '로그 메시지\n', (err) => {
if (err) throw err;
console.log('로그가 추가되었습니다.');
});
4.2 writeFile의 'a' 플래그 사용
const fs = require('fs').promises;
await fs.writeFile('log.txt', '새로운 항목\n', { flag: 'a' });
5. 파일 핸들 사용
파일 핸들을 사용하면 더 세밀한 제어가 가능합니다.
const fs = require('fs').promises;
async function useFileHandle() {
let fileHandle;
try {
// 파일 열기
fileHandle = await fs.open('example.txt', 'r+');
// 파일 읽기
const { buffer, bytesRead } = await fileHandle.read(
Buffer.alloc(100), // 버퍼
0, // 버퍼 오프셋
100, // 읽을 바이트 수
0 // 파일 오프셋
);
console.log(buffer.toString('utf8', 0, bytesRead));
// 파일 쓰기
await fileHandle.write('새로운 내용', 0, 'utf8');
// 파일 정보 가져오기
const stats = await fileHandle.stat();
console.log('파일 크기:', stats.size);
} finally {
// 파일 핸들 닫기 (중요!)
if (fileHandle) {
await fileHandle.close();
}
}
}
6. 부분 읽기/쓰기
6.1 특정 위치에서 읽기
const fs = require('fs');
// 저수준 API 사용
fs.open('large-file.txt', 'r', (err, fd) => {
if (err) throw err;
const buffer = Buffer.alloc(100);
// 파일의 50번째 바이트부터 100바이트 읽기
fs.read(fd, buffer, 0, 100, 50, (err, bytesRead, buffer) => {
if (err) throw err;
console.log(buffer.toString('utf8', 0, bytesRead));
fs.close(fd, () => {});
});
});
6.2 특정 위치에 쓰기
const fs = require('fs');
fs.open('example.txt', 'r+', (err, fd) => {
if (err) throw err;
const data = Buffer.from('INSERT');
// 파일의 10번째 위치에 쓰기
fs.write(fd, data, 0, data.length, 10, (err) => {
if (err) throw err;
fs.close(fd, () => {});
});
});
7. JSON 파일 다루기
const fs = require('fs').promises;
// JSON 읽기
async function readJSON(filepath) {
const data = await fs.readFile(filepath, 'utf8');
return JSON.parse(data);
}
// JSON 쓰기
async function writeJSON(filepath, data) {
const json = JSON.stringify(data, null, 2);
await fs.writeFile(filepath, json, 'utf8');
}
// 사용 예시
async function main() {
// 읽기
const config = await readJSON('config.json');
console.log(config);
// 수정 후 저장
config.version = '2.0.0';
await writeJSON('config.json', config);
}
8. 파일 존재 여부 확인
const fs = require('fs').promises;
// access 사용 (권장)
async function fileExists(filepath) {
try {
await fs.access(filepath, fs.constants.F_OK);
return true;
} catch {
return false;
}
}
// stat 사용
async function checkFile(filepath) {
try {
const stats = await fs.stat(filepath);
return stats.isFile();
} catch {
return false;
}
}
// 동기 방식
const existsSync = fs.existsSync('example.txt'); // true/false
9. 실전 예시
9.1 설정 파일 관리
const fs = require('fs').promises;
const path = require('path');
class ConfigManager {
constructor(configPath) {
this.configPath = configPath;
}
async load() {
try {
const data = await fs.readFile(this.configPath, 'utf8');
return JSON.parse(data);
} catch (err) {
if (err.code === 'ENOENT') {
return {}; // 파일이 없으면 빈 객체 반환
}
throw err;
}
}
async save(config) {
const dir = path.dirname(this.configPath);
await fs.mkdir(dir, { recursive: true });
await fs.writeFile(
this.configPath,
JSON.stringify(config, null, 2),
'utf8'
);
}
async update(updates) {
const config = await this.load();
const newConfig = { ...config, ...updates };
await this.save(newConfig);
return newConfig;
}
}
// 사용
const config = new ConfigManager('./config/app.json');
await config.update({ theme: 'dark', language: 'ko' });
9.2 로그 파일 관리
const fs = require('fs').promises;
class Logger {
constructor(logPath) {
this.logPath = logPath;
}
async log(level, message) {
const timestamp = new Date().toISOString();
const logEntry = `[${timestamp}] [${level}] ${message}\n`;
await fs.appendFile(this.logPath, logEntry, 'utf8');
}
info(message) {
return this.log('INFO', message);
}
error(message) {
return this.log('ERROR', message);
}
async readLogs() {
try {
return await fs.readFile(this.logPath, 'utf8');
} catch {
return '';
}
}
}
const logger = new Logger('./logs/app.log');
await logger.info('애플리케이션 시작');
await logger.error('오류 발생');
결론
Node.js의 fs 모듈은 파일 읽기와 쓰기를 위한 다양한 메서드를 제공합니다. readFile/writeFile로 간단한 작업을, 파일 핸들을 사용해 세밀한 제어를 할 수 있습니다. Promise 기반 API(fs.promises)를 사용하면 async/await과 함께 깔끔한 비동기 코드를 작성할 수 있습니다. 파일 작업 시에는 반드시 에러 처리를 해야 하며, 파일 핸들을 열었다면 반드시 닫아야 합니다.
728x90
반응형
'Node.js' 카테고리의 다른 글
| Node.js의 이벤트 에미터(EventEmitter) 사용법 (0) | 2026.02.25 |
|---|---|
| Node.js의 타이머 함수(Timer Functions) (0) | 2026.02.25 |
| Node.js의 콘솔 객체(console object) (0) | 2026.02.25 |
| Node.js의 프로세스 객체(process object) (0) | 2026.02.25 |
| Node.js의 글로벌 객체(Global Objects) (0) | 2026.02.24 |