Foruma hoş geldin 👋, Ziyaretçi

Forum içeriğine ve tüm hizmetlerimize erişim sağlamak için foruma kayıt olmalı ya da giriş yapmalısınız. Foruma üye olmak tamamen ücretsizdir.

Node.js'te stream kullanarak büyük dosya işlemlerinde memory kullanımını optimize etme

✖ Kapat
Duyuru
✖ Kapat
Duyuru

stackor

Üye
Katılım
14 Mart 2026
Mesajlar
53
Merhaba arkadaşlar, bugün başımı çok ağrıtan bir sorunu ve nasıl çözdüğümü anlatacağım. Bir projede, kullanıcıların yüklediği GB'larca CSV ve log dosyalarını işlemem gerekiyordu. İlk başta klasik `fs.readFile` ile okuduğumda, sunucu belleği kısa sürede tükeniyor ve uygulama çöküyordu. Bu hatayı ilk gördüğümde kafayı yemiştim, çünkü dosya boyutu arttıkça memory kullanımı da doğru orantılı artıyordu.

İşte o zaman Node.js'in güçlü yanlarından biri olan Stream'lerin nimetlerinden faydalanmaya karar verdim. Stream'ler, veriyi küçük parçalar (chunk'lar) halinde okuyup işleyerek, tüm dosyayı bir kerede belleğe yüklemekten kurtarıyor. Bu sayede 10GB'lık bir dosyayı işlerken bile memory kullanımınız birkaç MB'ı geçmiyor.

🔥 Karşılaştığım Sorun ve Naif Çözüm
İlk denememdeki kod buydu. Küçük dosyalar için çalışsa da, büyükler için felaketti:

JavaScript:
const fs = require('fs');
const processData = (filePath) => {
  // TÜM DOSYA BELLEĞE YÜKLENİYOR!
  fs.readFile(filePath, 'utf8', (err, data) => {
    if (err) throw err;
    const lines = data.split('\n');
    lines.forEach(line => {
      // Her satırı işle...
      console.log(line);
    });
  });
};

Bu yöntemde, `data` değişkeni tüm dosya içeriğini tuttuğu için, dosya ne kadar büyükse o kadar çok RAM tüketiyordu.

🚀 Stream'lerle Gelen Kurtuluş
Çözüm, veriyi bir nehir gibi akıtmakta yatıyor. `fs.createReadStream` ile bir okuma stream'i oluşturup, `readline` modülü ile satır satır işliyoruz.

JavaScript:
const fs = require('fs');
const readline = require('readline');

const processLargeFile = (filePath) => {
  return new Promise((resolve, reject) => {
    const fileStream = fs.createReadStream(filePath, { encoding: 'utf8' });
    
    // Readline interface'i oluştur
    const rl = readline.createInterface({
      input: fileStream,
      crlfDelay: Infinity // Tüm CRLF (\r\n) ve LF (\n) satır sonlarını düzgün yakala
    });

    let lineCount = 0;

    // 'line' eventi, her yeni satır okunduğunda tetiklenir
    rl.on('line', (line) => {
      lineCount++;
      // Burada satırı işliyoruz. Sadece o anki satır bellekte.
      // Örnek: CSV parsing, log analizi, veri filtreme
      // console.log(`Satır ${lineCount}: ${line.substring(0, 50)}...`);
      
      // ÖNEMLİ: Bu callback içinde ağır senkron işlemler YAPMA.
      // Ağır işlemler için worker thread veya queue düşün.
    });

    // Stream bittiğinde
    rl.on('close', () => {
      console.log(`Dosya işlendi. Toplam satır: ${lineCount}`);
      resolve(lineCount);
    });

    // Hata durumunda
    fileStream.on('error', (err) => {
      reject(err);
    });
  });
};

// Kullanımı
(async () => {
  try {
    await processLargeFile('devasa_log_file.log');
  } catch (error) {
    console.error('Dosya işlenirken hata:', error);
  }
})();

Bu yapıda, dosya tek seferde değil, küçük parçalar halinde okunuyor. `readline` modülü, bu parçaları satır sonlarına (`\n`) göre ayırıp bize tek tek `line` eventi olarak sunuyor. Bellekte sadece o an işlenen satır bulunuyor.

💡 İleri Seviye Optimizasyon: Pipeline ve Transform Stream
Eğer veriyi okurken aynı anda dönüştürmeniz gerekiyorsa (örn: CSV'den JSON'a, veri temizleme), Node.js'in dahili `stream.Transform` sınıfı mükemmel bir seçenek. İşte bir örnek:

JavaScript:
const { Transform, pipeline } = require('stream');
const fs = require('fs');
const csv = require('csv-parser'); // Örnek bir parser

// Özel bir Transform Stream oluşturalım
const jsonTransformer = new Transform({
  objectMode: true, // JavaScript objeleri ile çalışıyoruz
  transform(chunk, encoding, callback) {
    // 'chunk' burada csv-parser'dan gelen bir satır objesi
    // Veriyi dönüştür
    const transformedData = {
      id: chunk.id,
      name: chunk.name.toUpperCase(),
      timestamp: new Date()
    };
    // Dönüştürülmüş veriyi bir sonraki adıma ilet
    this.push(JSON.stringify(transformedData) + '\n');
    callback();
  }
});

// Pipeline ile akışı birleştir
pipeline(
  fs.createReadStream('large_data.csv'),
  csv(), // CSV'yi parse eden stream
  jsonTransformer, // Bizim dönüştürücümüz
  fs.createWriteStream('output.jsonl'),
  (err) => {
    if (err) {
      console.error('Pipeline hatası:', err);
    } else {
      console.log('Dönüştürme tamamlandı!');
    }
  }
);

`pipeline` fonksiyonu, stream'leri birbirine bağlar ve hata yönetimini merkezileştirir. Bu, `.pipe()` kullanmaktan daha güvenli ve modern bir yöntem.

Sonuç olarak, büyük veri işlemlerinde stream kullanmak bir lüks değil, bir zorunluluk. Bu yöntemle uygulamamın memory kullanımı %95 oranında azaldı ve GB'larca dosyayı sorunsuz işleyebilir hale geldim.

Siz Node.js projelerinizde büyük dosyaları nasıl işliyorsunuz? `readline` dışında tercih ettiğiniz stream kütüphaneleri var mı? Yaşadığınız ilginç performans sorunlarını ve çözümlerinizi yorumlarda paylaşın, tartışalım!
 

Tema özelleştirme sistemi

Bu menüden forum temasının bazı alanlarını kendinize özel olarak düzenleye bilirsiniz.

Zevkine göre renk kombinasyonunu belirle

Tam ekran yada dar ekran

Temanızın gövde büyüklüğünü sevkiniz, ihtiyacınıza göre dar yada geniş olarak kulana bilirsiniz.

Geri