728x90
반응형
1. 디렉토리 생성
1.1 mkdir - 디렉토리 생성
const fs = require('fs');
// 콜백 방식
fs.mkdir('new-folder', (err) => {
if (err) {
console.error('디렉토리 생성 오류:', err);
return;
}
console.log('디렉토리가 생성되었습니다.');
});
// 동기 방식
try {
fs.mkdirSync('new-folder');
console.log('디렉토리가 생성되었습니다.');
} catch (err) {
console.error('오류:', err);
}
1.2 Promise 기반 생성
const fs = require('fs').promises;
async function createDirectory(dirPath) {
try {
await fs.mkdir(dirPath);
console.log('디렉토리가 생성되었습니다.');
} catch (err) {
if (err.code === 'EEXIST') {
console.log('디렉토리가 이미 존재합니다.');
} else {
throw err;
}
}
}
await createDirectory('my-folder');
1.3 재귀적 생성 (recursive)
중첩된 디렉토리를 한 번에 생성합니다.
const fs = require('fs').promises;
// 중첩 디렉토리 생성
await fs.mkdir('path/to/deep/folder', { recursive: true });
// 이미 존재해도 오류 없음
await fs.mkdir('existing/path', { recursive: true });
// 생성된 첫 번째 디렉토리 경로 반환
const created = await fs.mkdir('a/b/c', { recursive: true });
console.log(created); // 'a' 또는 undefined (이미 존재할 경우)
1.4 권한 지정
const fs = require('fs').promises;
// 권한과 함께 생성
await fs.mkdir('secure-folder', {
recursive: true,
mode: 0o755 // rwxr-xr-x
});
// 제한적 권한
await fs.mkdir('private-folder', {
mode: 0o700 // rwx------
});
2. 디렉토리 삭제
2.1 rmdir - 빈 디렉토리 삭제
const fs = require('fs');
// 콜백 방식 (빈 디렉토리만)
fs.rmdir('empty-folder', (err) => {
if (err) {
if (err.code === 'ENOTEMPTY') {
console.log('디렉토리가 비어있지 않습니다.');
} else {
console.error('오류:', err);
}
return;
}
console.log('디렉토리가 삭제되었습니다.');
});
// 동기 방식
try {
fs.rmdirSync('empty-folder');
} catch (err) {
console.error('오류:', err);
}
2.2 rm - 디렉토리 재귀 삭제 (Node.js 14.14+)
const fs = require('fs').promises;
// 디렉토리와 내용물 모두 삭제
await fs.rm('folder-with-files', { recursive: true });
// 존재하지 않아도 오류 없이 진행
await fs.rm('maybe-exists', { recursive: true, force: true });
// 콜백 방식
fs.rm('folder', { recursive: true, force: true }, (err) => {
if (err) throw err;
console.log('삭제 완료');
});
2.3 Promise 기반 삭제
const fs = require('fs').promises;
async function removeDirectory(dirPath, options = {}) {
const { force = false } = options;
try {
await fs.rm(dirPath, { recursive: true, force });
console.log(`${dirPath} 삭제 완료`);
return true;
} catch (err) {
if (err.code === 'ENOENT' && force) {
return true; // 존재하지 않아도 성공
}
throw err;
}
}
await removeDirectory('old-folder', { force: true });
3. 디렉토리 읽기
3.1 readdir - 디렉토리 내용 읽기
const fs = require('fs').promises;
// 파일/폴더 이름 목록
const files = await fs.readdir('my-folder');
console.log(files); // ['file1.txt', 'file2.txt', 'subfolder']
// 파일 타입 정보 포함
const entries = await fs.readdir('my-folder', { withFileTypes: true });
for (const entry of entries) {
if (entry.isFile()) {
console.log(`파일: ${entry.name}`);
} else if (entry.isDirectory()) {
console.log(`폴더: ${entry.name}`);
}
}
3.2 재귀적 읽기
const fs = require('fs').promises;
const path = require('path');
async function readDirRecursive(dir) {
const result = [];
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
const subFiles = await readDirRecursive(fullPath);
result.push(...subFiles);
} else {
result.push(fullPath);
}
}
return result;
}
const allFiles = await readDirRecursive('./src');
console.log(allFiles);
3.3 recursive 옵션 (Node.js 18.17+)
const fs = require('fs').promises;
// 재귀적으로 모든 파일/폴더 읽기
const allEntries = await fs.readdir('src', { recursive: true });
console.log(allEntries);
// ['file1.js', 'components', 'components/Button.js', ...]
반응형
4. 디렉토리 존재 확인
const fs = require('fs').promises;
// access 사용
async function directoryExists(dirPath) {
try {
await fs.access(dirPath);
const stats = await fs.stat(dirPath);
return stats.isDirectory();
} catch {
return false;
}
}
// 사용
if (await directoryExists('my-folder')) {
console.log('디렉토리가 존재합니다.');
}
// 동기 방식
const exists = fs.existsSync('my-folder') &&
fs.statSync('my-folder').isDirectory();
5. 디렉토리 정보 조회
const fs = require('fs').promises;
async function getDirectoryInfo(dirPath) {
const stats = await fs.stat(dirPath);
return {
isDirectory: stats.isDirectory(),
size: stats.size,
created: stats.birthtime,
modified: stats.mtime,
accessed: stats.atime,
mode: stats.mode.toString(8)
};
}
const info = await getDirectoryInfo('my-folder');
console.log(info);
6. 디렉토리 복사
6.1 cp 사용 (Node.js 16.7+)
const fs = require('fs').promises;
// 디렉토리 전체 복사
await fs.cp('source-folder', 'dest-folder', { recursive: true });
// 옵션 지정
await fs.cp('src', 'dst', {
recursive: true,
force: true, // 기존 파일 덮어쓰기
preserveTimestamps: true,
filter: (src) => !src.includes('node_modules')
});
6.2 수동 구현
const fs = require('fs').promises;
const path = require('path');
async function copyDirectory(src, dest) {
await fs.mkdir(dest, { recursive: true });
const entries = await fs.readdir(src, { withFileTypes: true });
for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const destPath = path.join(dest, entry.name);
if (entry.isDirectory()) {
await copyDirectory(srcPath, destPath);
} else {
await fs.copyFile(srcPath, destPath);
}
}
}
await copyDirectory('source', 'backup');
7. 임시 디렉토리
7.1 mkdtemp - 임시 디렉토리 생성
const fs = require('fs').promises;
const os = require('os');
const path = require('path');
// 시스템 임시 폴더에 생성
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'myapp-'));
console.log(tempDir); // /tmp/myapp-abc123
// 작업 수행
// ...
// 정리
await fs.rm(tempDir, { recursive: true });
7.2 임시 디렉토리 관리 클래스
const fs = require('fs').promises;
const os = require('os');
const path = require('path');
class TempDirectory {
constructor(prefix = 'tmp') {
this.prefix = prefix;
this.path = null;
}
async create() {
this.path = await fs.mkdtemp(
path.join(os.tmpdir(), `${this.prefix}-`)
);
return this.path;
}
async cleanup() {
if (this.path) {
await fs.rm(this.path, { recursive: true, force: true });
this.path = null;
}
}
getPath(...subPaths) {
return path.join(this.path, ...subPaths);
}
}
// 사용
const temp = new TempDirectory('build');
await temp.create();
try {
// 임시 폴더에서 작업
await fs.writeFile(temp.getPath('output.txt'), 'data');
} finally {
await temp.cleanup();
}
8. 실전 예시
8.1 프로젝트 구조 생성기
const fs = require('fs').promises;
const path = require('path');
async function createProjectStructure(rootDir, structure) {
await fs.mkdir(rootDir, { recursive: true });
for (const [name, content] of Object.entries(structure)) {
const fullPath = path.join(rootDir, name);
if (typeof content === 'object') {
// 디렉토리인 경우 재귀
await createProjectStructure(fullPath, content);
} else {
// 파일인 경우 생성
await fs.mkdir(path.dirname(fullPath), { recursive: true });
await fs.writeFile(fullPath, content);
}
}
}
// 프로젝트 구조 정의
const structure = {
'src': {
'index.js': 'console.log("Hello");',
'utils': {
'helpers.js': 'module.exports = {};'
}
},
'tests': {
'index.test.js': 'test("example", () => {});'
},
'package.json': '{"name": "my-project"}',
'README.md': '# My Project'
};
await createProjectStructure('my-new-project', structure);
8.2 디렉토리 크기 계산
const fs = require('fs').promises;
const path = require('path');
async function getDirectorySize(dirPath) {
let totalSize = 0;
const entries = await fs.readdir(dirPath, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name);
if (entry.isDirectory()) {
totalSize += await getDirectorySize(fullPath);
} else {
const stats = await fs.stat(fullPath);
totalSize += stats.size;
}
}
return totalSize;
}
function formatSize(bytes) {
const units = ['B', 'KB', 'MB', 'GB'];
let unitIndex = 0;
let size = bytes;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(2)} ${units[unitIndex]}`;
}
const size = await getDirectorySize('./node_modules');
console.log('총 크기:', formatSize(size));
8.3 디렉토리 감시 및 정리
const fs = require('fs').promises;
const path = require('path');
async function cleanOldFiles(dirPath, maxAgeDays) {
const cutoff = Date.now() - (maxAgeDays * 24 * 60 * 60 * 1000);
const entries = await fs.readdir(dirPath, { withFileTypes: true });
let deletedCount = 0;
let deletedSize = 0;
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name);
const stats = await fs.stat(fullPath);
if (stats.mtimeMs < cutoff) {
if (entry.isDirectory()) {
await fs.rm(fullPath, { recursive: true });
} else {
deletedSize += stats.size;
await fs.unlink(fullPath);
}
deletedCount++;
}
}
return { deletedCount, deletedSize };
}
// 30일 이상된 파일 정리
const result = await cleanOldFiles('./temp', 30);
console.log(`${result.deletedCount}개 삭제, ${result.deletedSize} bytes 확보`);
8.4 디렉토리 동기화
const fs = require('fs').promises;
const path = require('path');
async function syncDirectories(source, target) {
await fs.mkdir(target, { recursive: true });
const sourceEntries = await fs.readdir(source, { withFileTypes: true });
const targetEntries = await fs.readdir(target, { withFileTypes: true });
const targetNames = new Set(targetEntries.map(e => e.name));
// 소스에 있는 파일 복사/업데이트
for (const entry of sourceEntries) {
const sourcePath = path.join(source, entry.name);
const targetPath = path.join(target, entry.name);
if (entry.isDirectory()) {
await syncDirectories(sourcePath, targetPath);
} else {
const sourceStats = await fs.stat(sourcePath);
try {
const targetStats = await fs.stat(targetPath);
// 소스가 더 최신이면 복사
if (sourceStats.mtimeMs > targetStats.mtimeMs) {
await fs.copyFile(sourcePath, targetPath);
}
} catch {
// 타겟에 없으면 복사
await fs.copyFile(sourcePath, targetPath);
}
}
targetNames.delete(entry.name);
}
// 소스에 없는 타겟 파일 삭제
for (const name of targetNames) {
const targetPath = path.join(target, name);
await fs.rm(targetPath, { recursive: true });
}
}
await syncDirectories('./source', './backup');
결론
Node.js에서 디렉토리 생성은 mkdir, 삭제는 rmdir 또는 rm을 사용합니다. recursive 옵션을 사용하면 중첩된 디렉토리를 한 번에 생성하거나 내용물이 있는 디렉토리를 삭제할 수 있습니다. mkdtemp로 임시 디렉토리를 생성하고, Node.js 16.7+의 cp로 디렉토리를 복사할 수 있습니다. 디렉토리 작업 시에는 경로 처리를 위해 path 모듈과 함께 사용하는 것이 좋습니다.
728x90
반응형
'Node.js' 카테고리의 다른 글
| Node.js의 파일 스트림 처리 (0) | 2026.03.07 |
|---|---|
| Node.js의 파일 삭제 및 이동 (0) | 2026.03.02 |
| Node.js의 파일 읽기와 쓰기 (0) | 2026.02.28 |
| Node.js의 이벤트 에미터(EventEmitter) 사용법 (0) | 2026.02.25 |
| Node.js의 타이머 함수(Timer Functions) (0) | 2026.02.25 |