Node.js File System: Dosya İşlemleri Rehberi

Node.js File System: Dosya İşlemleri Rehberi
Node.js'in fs (File System) modülü, dosya ve dizin işlemlerini gerçekleştirmek için kapsamlı bir API sunar. Dosya okuma/yazma, dizin oluşturma, dosya izleme ve path yönetimi gibi temel işlemlerden, stream tabanlı büyük dosya işlemeye kadar birçok senaryo bu modül ile yönetilir. Bu rehberde fs modülünün modern kullanımını — promises API, async/await pattern'leri ve güvenli dosya işlemleri — detaylı örneklerle inceleyeceğiz.
1. fs/promises: Modern Dosya İşlemleri
Node.js 14+ ile birlikte gelen fs/promises modülü, dosya işlemlerini Promise tabanlı olarak gerçekleştirmenizi sağlar. Callback tabanlı eski API yerine async/await ile temiz ve okunabilir kod yazabilirsiniz. Tüm yeni projelerde fs/promises kullanmanız önerilir.
const fs = require('fs/promises');
const path = require('path');
// Dosya okuma
async function readFile(filePath) {
try {
const content = await fs.readFile(filePath, 'utf-8');
return content;
} catch (error) {
if (error.code === 'ENOENT') {
console.error(`Dosya bulunamadı: ${filePath}`);
return null;
}
throw error;
}
}
// JSON dosyası okuma/yazma
async function readJSON(filePath) {
const content = await fs.readFile(filePath, 'utf-8');
return JSON.parse(content);
}
async function writeJSON(filePath, data) {
const content = JSON.stringify(data, null, 2);
await fs.writeFile(filePath, content, 'utf-8');
}
// Dosya yazma (güvenli - geçici dosya ile)
async function safeWriteFile(filePath, content) {
const tempPath = `${filePath}.tmp`;
try {
await fs.writeFile(tempPath, content, 'utf-8');
await fs.rename(tempPath, filePath);
} catch (error) {
// Geçici dosyayı temizle
try { await fs.unlink(tempPath); } catch {}
throw error;
}
}
// Dosya/dizin varlık kontrolü
async function exists(filePath) {
try {
await fs.access(filePath);
return true;
} catch {
return false;
}
}
// Dosya bilgisi
async function getFileInfo(filePath) {
const stats = await fs.stat(filePath);
return {
size: stats.size,
sizeHuman: formatBytes(stats.size),
isFile: stats.isFile(),
isDirectory: stats.isDirectory(),
created: stats.birthtime,
modified: stats.mtime,
permissions: stats.mode.toString(8).slice(-3)
};
}
function formatBytes(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
2. Dizin İşlemleri ve Recursive Operasyonlar
Dizin oluşturma, listeleme, kopyalama ve silme işlemleri, dosya tabanlı uygulamaların temel gereksinimlerindendir. Node.js 16+ ile birlikte recursive dizin operasyonları native olarak desteklenir.
// Dizin oluşturma (recursive)
async function ensureDir(dirPath) {
await fs.mkdir(dirPath, { recursive: true });
}
// Dizin içeriğini listele (recursive)
async function listFiles(dirPath, options = {}) {
const { recursive = false, extensions = null } = options;
const entries = await fs.readdir(dirPath, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name);
if (entry.isDirectory() && recursive) {
const subFiles = await listFiles(fullPath, options);
files.push(...subFiles);
} else if (entry.isFile()) {
if (!extensions || extensions.includes(path.extname(entry.name))) {
files.push({
name: entry.name,
path: fullPath,
ext: path.extname(entry.name)
});
}
}
}
return files;
}
// Dizin kopyalama
async function copyDir(src, dest) {
await ensureDir(dest);
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 copyDir(srcPath, destPath);
} else {
await fs.copyFile(srcPath, destPath);
}
}
}
// Dizin boyutunu hesapla
async function getDirSize(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 getDirSize(fullPath);
} else {
const stats = await fs.stat(fullPath);
totalSize += stats.size;
}
}
return totalSize;
}
// Kullanım
const jsFiles = await listFiles('./src', {
recursive: true,
extensions: ['.js', '.ts']
});
console.log(`Toplam ${jsFiles.length} dosya bulundu`);
3. Path Modülü: Platform Bağımsız Yol Yönetimi
path modülü, dosya yollarını platform bağımsız şekilde yönetmenizi sağlar. Windows ve Unix sistemlerinin farklı yol ayırıcıları kullandığını göz önünde bulundurarak, her zaman path modülü fonksiyonlarını kullanmalısınız.
const path = require('path');
// Temel path operasyonları
const filePath = '/home/user/projects/app/src/index.js';
console.log(path.basename(filePath)); // 'index.js'
console.log(path.basename(filePath, '.js')); // 'index'
console.log(path.dirname(filePath)); // '/home/user/projects/app/src'
console.log(path.extname(filePath)); // '.js'
// Yol birleştirme (.. ile normalize eder)
const configPath = path.join(__dirname, '..', 'config', 'app.json');
// Mutlak yol oluşturma
const absolutePath = path.resolve('src', 'utils', 'helpers.js');
// Yol ayrıştırma
const parsed = path.parse(filePath);
// { root: '/', dir: '/home/user/projects/app/src',
// base: 'index.js', ext: '.js', name: 'index' }
// Upload dosyası için güvenli dosya adı oluşturma
function generateSafeFilename(originalName) {
const ext = path.extname(originalName).toLowerCase();
const allowedExts = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.pdf'];
if (!allowedExts.includes(ext)) {
throw new Error(`Desteklenmeyen dosya türü: ${ext}`);
}
const timestamp = Date.now();
const random = Math.random().toString(36).substring(2, 8);
return `${timestamp}-${random}${ext}`;
}
4. Dosya İzleme (File Watching)
fs.watch API'si ile dosya ve dizin değişikliklerini gerçek zamanlı olarak izleyebilirsiniz. Bu özellik, development araçları, hot-reload mekanizmaları ve log izleme gibi senaryolarda kullanılır. Ancak fs.watch platformlar arası tutarsızlıklar gösterebilir; production uygulamalarında chokidar gibi kütüphaneler tercih edilmelidir.
AbortController ile watcher'ları programatik olarak durdurabilirsiniz. Recursive watching desteği, bir dizin altındaki tüm değişiklikleri tek bir watcher ile izlemenizi sağlar. Dosya izleme sırasında debounce mekanizması uygulamak, aynı dosya için art arda tetiklenen gereksiz olayları filtrelemenize yardımcı olur.
Sonuç
Node.js'in File System modülü, dosya ve dizin işlemleri için güçlü ve esnek bir API sunar. fs/promises ile modern async/await pattern'lerini kullanarak temiz ve güvenli dosya işlemleri gerçekleştirebilirsiniz. Path modülü ile platform bağımsız yol yönetimi, güvenli dosya yazma pattern'leri ve file watching mekanizmaları, Node.js ile dosya tabanlı uygulamalar geliştirmenin temellerini oluşturur.