1. Node.js fs
모듈 소개
1.1 fs
모듈의 중요성
Node.js의 fs
모듈은 파일 및 디렉토리 작업을 위한 핵심 API를 제공합니다. 이 모듈을 통해 파일의 생성, 수정, 삭제뿐만 아니라 디렉토리 관리까지 가능합니다.
1.2 비동기 및 동기 방식
fs
모듈은 비동기(Asynchronous) 및 동기(Synchronous) 방식 모두를 지원합니다.
- 비동기 방식: I/O 작업이 완료될 때까지 기다리지 않고 다음 코드를 실행하여, 서버 환경에서 높은 성능을 유지할 수 있습니다. 주로 콜백 함수를 사용하여 작업 완료 후 결과를 처리합니다.
- 동기 방식: I/O 작업이 완료될 때까지 코드 실행이 중단됩니다. 단순 스크립트나 테스트 환경에서 직관적이고 쉽게 사용할 수 있습니다.
2. 파일 읽기 (File Reading)
2.1 비동기 파일 읽기
비동기 방식으로 파일을 읽을 때는 fs.readFile()
메서드를 사용합니다.
2.1.1 기본 사용법
const fs = require('fs');
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error reading file:', err);
return;
}
console.log('File data (basic):', data);
});
example.txt
: 읽을 파일의 경로를 지정합니다.utf8
: 텍스트 파일의 인코딩 방식을 지정합니다.- 콜백 함수: 파일 읽기 작업 완료 후, 에러 객체
err
와 파일 데이터data
를 인자로 받는 함수입니다.
2.1.2 예외 처리 및 다양한 시나리오
// 파일이 존재하지 않을 때
fs.readFile('nonexistent.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error reading nonexistent file:', err.code);
return;
}
console.log('File data (nonexistent):', data);
});
// 큰 파일 처리
fs.readFile('large_file.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error reading large file:', err);
return;
}
console.log('File data (large file):', data.substring(0, 100) + '...');
});
// 다른 인코딩 방식 사용
fs.readFile('ascii_text.txt', 'ascii', (err, data) => {
if (err) {
console.error('Error reading ascii file:', err);
return;
}
console.log('File data (ascii):', data);
});
2.2 동기 파일 읽기
동기 방식으로 파일을 읽을 때는 fs.readFileSync()
메서드를 사용합니다.
2.2.1 기본 사용법
const fs = require('fs');
try {
const data = fs.readFileSync('example.txt', 'utf8');
console.log('File data (sync basic):', data);
} catch (err) {
console.error('Error reading file (sync basic):', err);
}
- 동기 방식은
try...catch
구문을 사용하여 에러를 처리해야 합니다.
2.2.2 다양한 시나리오 및 예외 처리
// 파일이 없을 때
try {
const data = fs.readFileSync('nonexistent.txt', 'utf8');
console.log('File data (sync nonexistent):', data);
} catch (err) {
console.error('Error reading nonexistent file (sync):', err.code);
}
// 바이너리 파일 처리
try {
const data = fs.readFileSync('binary_file.dat', 'base64');
console.log('File data (sync base64):', data.substring(0, 50) + '...');
} catch (err) {
console.error('Error reading binary file (sync):', err);
}
// 빈 파일 처리
try {
const data = fs.readFileSync('empty_file.txt', 'utf8');
console.log('File data (sync empty):', data ? data : "(파일 내용 없음)");
} catch (err) {
console.error('Error reading empty file (sync):', err);
}
2.3 실용적인 활용 사례
설정 정보를 JSON 파일로 관리하는 경우를 살펴봅니다.
2.3.1 JSON 설정 파일 읽기
// config.json
// {
// "port": 3000,
// "db": "mongodb://localhost/myapp",
// "logLevel": "debug",
// "apiKeys": ["key123", "key456"]
// }
const fs = require('fs');
fs.readFile('config.json', 'utf8', (err, data) => {
if (err) throw err;
const config = JSON.parse(data);
console.log(`Server port: ${config.port}`);
console.log(`Database URL: ${config.db}`);
console.log(`Log Level: ${config.logLevel}`);
console.log(`API Keys: ${config.apiKeys.join(', ')}`);
});
2.3.2 JSON 파싱 오류 처리 및 특정 값 추출
// JSON 형식이 아닌 파일 처리
fs.readFile('invalid_config.txt', 'utf8', (err, data) => {
if (err) {
console.error("Error reading invalid config:", err);
} else {
try {
const config = JSON.parse(data);
console.log("Invalid config parsed:", config)
} catch (parseErr) {
console.error("Error parsing invalid config:", parseErr);
}
}
});
// 특정 설정 값 추출
fs.readFile('config.json', 'utf8', (err, data) => {
if (err) throw err;
const config = JSON.parse(data);
console.log(`Only Port : ${config.port}`);
});
// 설정 값 없을 경우 기본값 설정
fs.readFile('config.json', 'utf8', (err, data) => {
if (err) throw err;
const config = JSON.parse(data);
const apiKeys = config.apiKeys || [];
console.log(`API Keys with default: ${apiKeys.join(', ')}`);
});
3. 파일 쓰기 (File Writing)
3.1 비동기 파일 쓰기
비동기 방식으로 파일을 쓸 때는 fs.writeFile()
메서드를 사용합니다.
3.1.1 기본 사용법
const fs = require('fs');
const data = 'Hello, this is the first file written by Node.js asynchronously!';
fs.writeFile('hello.txt', data, (err) => {
if (err) {
console.error('Error writing file (basic):', err);
} else {
console.log('File written successfully (basic).');
}
});
hello.txt
: 생성할 파일 경로를 지정합니다.data
: 파일에 쓸 데이터를 지정합니다.- 콜백 함수: 파일 쓰기 작업 완료 후, 에러 객체
err
를 인자로 받는 함수입니다.
3.1.2 다양한 데이터 및 시나리오
// JSON 데이터 쓰기
const jsonData = { message: 'This is JSON data.', version: '1.0' };
fs.writeFile('json_file.json', JSON.stringify(jsonData, null, 2), (err) => {
if (err) {
console.error('Error writing JSON file:', err);
} else {
console.log('JSON file written successfully.');
}
});
// 여러 줄 텍스트 데이터 쓰기
const multiLineData = "This is line 1.\nThis is line 2.\nThis is line 3.";
fs.writeFile('multi_line.txt', multiLineData, (err) => {
if (err) {
console.error('Error writing multi-line file:', err);
} else {
console.log("Multi-line file written successfully.")
}
});
// 기존 파일 덮어쓰기
const overwriteData = 'This will overwrite the content of file.';
fs.writeFile('hello.txt', overwriteData, (err) => {
if (err) {
console.error('Error overwriting file:', err);
} else {
console.log('File overwritten successfully.');
}
});
3.2 동기 파일 쓰기
동기 방식으로 파일을 쓸 때는 fs.writeFileSync()
메서드를 사용합니다.
3.2.1 기본 사용법
const fs = require('fs');
const data = 'Hello, this is the second file written by Node.js synchronously.';
try {
fs.writeFileSync('syncHello.txt', data);
console.log('File written successfully (sync basic).');
} catch (err) {
console.error('Error writing file (sync basic):', err);
}
- 동기 방식은
try...catch
구문을 사용하여 에러를 처리해야 합니다.
3.2.2 다양한 데이터 및 시나리오
// 바이너리 데이터 쓰기
const binaryData = Buffer.from('This is binary data.', 'utf-8');
try {
fs.writeFileSync('binary_data.dat', binaryData);
console.log('Binary file written successfully.');
} catch (err) {
console.error('Error writing binary file:', err);
}
// 다른 인코딩으로 쓰기
const asciiData = 'This text is in ASCII.';
try {
fs.writeFileSync('ascii_file.txt', asciiData, { encoding: 'ascii' });
console.log("ASCII file written successfully.");
} catch (err) {
console.error("Error writing ascii file:", err);
}
// 기존 파일에 내용 추가 (동기)
const syncAppendData = '\nThis is appended content sync.';
try {
fs.writeFileSync('hello.txt', syncAppendData, { flag: 'a' });
console.log("Content appended successfully using sync.");
} catch (err) {
console.error("Error appending content:", err);
}
3.3 파일 쓰기 옵션
파일 쓰기 메서드에는 추가적인 옵션을 지정하여 다양한 기능을 활용할 수 있습니다.
3.3.1 기본 추가 쓰기 및 인코딩
const fs = require('fs');
const additionalData = '\nThis content is appended to the existing file!';
fs.writeFile('hello.txt', additionalData, { flag: 'a' }, (err) => {
if (err) {
console.error('Error appending content (basic):', err);
} else {
console.log('Content appended successfully (basic).');
}
});
const encodedData = '\nThis is encoded data.';
fs.writeFile('hello.txt', encodedData, { flag: 'a', encoding: 'utf16le' }, (err) => {
if (err) {
console.error("Error appending content with encoding:", err)
} else {
console.log("Content appended successfully with encoding.");
}
});
3.3.2 파일 생성 또는 덮어쓰기 옵션
const fs = require('fs');
const createOrOverwriteData = 'This is content for new or overwritten file.';
fs.writeFile('new_or_overwrite.txt', createOrOverwriteData, { flag: 'w+' }, (err) => {
if (err) {
console.error("Error writing or creating file with flag:", err);
} else {
console.log("File created or overwritten successfully.");
}
});
4. 파일 삭제 (File Deletion)
4.1 비동기 파일 삭제
비동기 방식으로 파일을 삭제할 때는 fs.unlink()
메서드를 사용합니다.
4.1.1 기본 사용법
const fs = require('fs');
const filePath = './example.txt';
fs.unlink(filePath, (err) => {
if (err) {
console.error(`Error deleting file (basic): ${err}`);
return;
}
console.log('File deleted successfully (basic).');
});
4.1.2 예외 처리 및 다양한 시나리오
const fs = require('fs');
const nonExistentFilePath = './nonexistent.txt';
fs.unlink(nonExistentFilePath, (err) => {
if (err) {
console.error(`Error deleting nonexistent file: ${err.code}`);
return;
}
console.log("Nonexistent file deleted successfully(no error).");
});
const filesToDelete = ['./file1.txt', './file2.txt', './file3.txt'];
filesToDelete.forEach(file => {
fs.unlink(file, (err) => {
if (err) {
console.error(`Error deleting file ${file}: ${err.message}`);
return;
}
console.log(`File ${file} deleted successfully.`);
});
});
const readOnlyFile = './readonly_file.txt';
fs.unlink(readOnlyFile, (err) => {
if (err) {
console.error(`Error deleting read-only file: ${err.code}`);
return;
}
console.log(`Read-only file deleted successfully.`);
});
4.2 동기 파일 삭제
동기 방식으로 파일을 삭제할 때는 fs.unlinkSync()
메서드를 사용합니다.
4.2.1 기본 사용법
const fs = require('fs');
try {
const filePath = './example.txt';
fs.unlinkSync(filePath);
console.log('File deleted successfully (sync basic).');
} catch (err) {
console.error(`Error deleting file (sync basic): ${err}`);
}
4.2.2 예외 처리 및 다양한 시나리오
const fs = require('fs');
try {
const nonExistentFilePath = './nonexistent.txt';
fs.unlinkSync(nonExistentFilePath);
console.log("Nonexistent file deleted successfully(no error)");
} catch (err) {
console.error(`Error deleting nonexistent file (sync): ${err.code}`);
}
const filePathToDelete = './check_before_delete.txt';
if (fs.existsSync(filePathToDelete)) {
try {
fs.unlinkSync(filePathToDelete);
console.log('File deleted after checking if exist.');
} catch (err) {
console.error(`Error deleting checked file: ${err}`);
}
} else {
console.log(`File ${filePathToDelete} does not exist.`);
}
try {
const readOnlyFile = './readonly_file.txt';
fs.unlinkSync(readOnlyFile);
console.log(`Read only file deleted (no error).`);
} catch (err) {
console.error(`Error deleting read-only file (sync): ${err.code}`);
}
4.3 파일 삭제 시 주의사항
- 삭제 전에 파일 존재 여부를 확인하는 것이 좋습니다.
- 중요한 파일은 반드시 백업해야 합니다.
- 운영 체제에 따른 권한 문제를 고려해야 합니다.
- 에러 처리를 꼼꼼하게 해야 합니다.
5. 디렉토리 관리 (Directory Management)
5.1 디렉토리 생성
디렉토리를 생성할 때는 fs.mkdir()
메서드를 사용합니다.
5.1.1 기본 사용법
const fs = require('fs');
fs.mkdir('newDirectory', (err) => {
if (err) {
console.error('Error creating directory (basic):', err);
} else {
console.log('Directory created successfully (basic).');
}
});
5.1.2 예외 처리 및 다양한 시나리오
const fs = require('fs');
fs.mkdir('newDirectory', (err) => {
if (err) {
console.error('Error creating already existing directory:', err.code)
} else {
console.log("Already existing directory created successfully(no error).")
}
});
fs.mkdir('parentDir/childDir1/childDir2', { recursive: true }, (err) => {
if (err) {
console.error('Error creating directories (recursive):', err);
} else {
console.log('Parent and child directories created successfully.');
}
});
const dirToCreate = './newDirCheckExist';
if (!fs.existsSync(dirToCreate)) {
fs.mkdir(dirToCreate, (err) => {
if (err) {
console.error('Error creating directory with check:', err);
} else {
console.log('Directory created after checking if exists.');
}
})
} else {
console.log("Directory already exist. Skipping creating")
}
fs.mkdir('/root/forbiddenDir', (err) => {
if (err) {
console.error("Error creating forbidden directory", err.code)
} else {
console.log("Forbidden directory created successfully.");
}
});
5.2 디렉토리 삭제
디렉토리를 삭제할 때는 fs.rmdir()
또는 fs.rm()
메서드를 사용합니다.
5.2.1 fs.rmdir()
사용
비어 있는 디렉토리를 삭제할 때 사용합니다.
const fs = require('fs');
fs.rmdir('newDirectory', (err) => {
if (err) {
console.error('Error deleting directory (basic):', err);
} else {
console.log('Directory deleted successfully (basic).');
}
});
fs.rmdir('nonEmptyDir', (err) => {
if (err) {
console.error('Error deleting non-empty directory:', err.code);
} else {
console.log('Non-empty directory deleted successfully(no error).');
}
})
5.2.2 fs.rm()
사용
비어있지 않은 디렉토리를 강제로 삭제할 때 사용합니다.
const path = require("path");
const fs = require('fs');
const dirPath = path.join(__dirname, "nonEmptyDir");
fs.rm(dirPath, { recursive: true }, (err) => {
if (err) {
return console.error("Error deleting directory with content:", err);
}
console.log("Directory with content deleted successfully.");
});
const nonExistentDir = path.join(__dirname, 'nonExistentDir');
fs.rm(nonExistentDir, { recursive: true }, (err) => {
if (err) {
console.error('Error deleting nonexistent directory:', err.code);
} else {
console.log("Nonexistent directory deleted successfully(no error)");
}
});
const forbiddenDir = path.join(__dirname, '/root/forbiddenDir');
fs.rm(forbiddenDir, { recursive: true }, (err) => {
if (err) {
console.error("Error deleting forbidden directory", err.code);
} else {
console.log("Forbidden directory deleted successfully")
}
});
결론
이 가이드는 Node.js의 fs
모듈을 사용하여 파일 및 디렉토리를 효과적으로 관리하는 방법을 상세하게 제공합니다. 제시된 예제들을 통해 파일 읽기, 쓰기, 삭제, 그리고 디렉토리 생성 및 삭제와 같은 기본적인 작업은 물론, 발생 가능한 예외 상황과 다양한 시나리오에 대한 이해를 높일 수 있습니다. 이를 통해 실제 개발 환경에서 파일 시스템을 안전하고 효율적으로 관리하는 능력을 향상시킬 수 있습니다. Node.js 개발자로서 파일 시스템에 대한 깊은 이해는 필수적이며, 이 가이드가 여러분의 개발 여정에 도움이 되기를 바랍니다.
'프로그래밍 > Node.js' 카테고리의 다른 글
Node.js 웹 개발의 핵심, Express.js 완벽 가이드: 특징, 라우팅, 미들웨어, 템플릿 엔진까지 (0) | 2025.02.19 |
---|---|
Node.js로 시작하는 HTTP 서버 구축 완벽 가이드: 요청, 응답 (0) | 2025.02.18 |
Node.js 비동기 프로그래밍 완벽 가이드: 콜백부터 async/await까지 (1) | 2025.02.18 |
Node.js 모듈 시스템 완벽 가이드: 핵심 개념부터 활용까지 (0) | 2025.02.18 |
Node.js 완벽 가이드: 설치부터 npm 활용까지 (1) | 2025.02.18 |