Bvural41 1
Bvural41
emirhanHCL 1
emirhanHCL
kralhakan2009 1
kralhakan2009
Vahsi Uzman 1
Vahsi Uzman
Hikaye Ekle

[NODE JS] Buyuk Dosyalari Satir Satir Okuma

Türkiye'de ilk Mobil & PC Aynı Anda Metin2 Oyna. Triarchonline kalıcı ve uzun ömürlü yapısı ile 24 Temmuz'da açılıyor. | 1-99 Mobil Metin2 Triarch HEMEN TIKLA!

nodejs.png


[NODE JS] Buyuk Dosyalari Satir Satir Okuma​


Merhaba arkadaslar, bugun cok onemli bir konuyu ele alacagiz: buyuk dosyalari nasil verimli bir sekilde satir satir okuyabiliriz? Bu konu ozellikle log dosyalari, CSV dosyalari veya buyuk veri setleriyle calisan herkes icin kritik oneme sahip. Ben bir keresinde 4 GB'lik bir log dosyasini readFile ile okumaya calistim ve Node.js surecim "JavaScript heap out of memory" hatasiyla patlamisti. O gunden sonra stream tabanli okuma yontemlerini ogrenmek zorunda kaldim.

Neden Tum Dosyayi Okumamalisiniz?​


fs.readFile fonksiyonu dosyanin tamamini bellege yukler. Kucuk dosyalar icin bu sorun degildir ama dosya buyudukce ciddi sorunlar olusur. Node.js'in varsayilan bellek limiti yaklasik 1.5 GB'dir. 2 GB'lik bir dosyayi okumaya calisirsiniz ve uygulamaniz coker. Ayrica tum dosyayi bellege yuklediginizde garbage collector surekli calisir ve uygulamaniz yavaslar.

Cozum basit: dosyayi tum olarak bellege yuklemek yerine parcalar halinde, satir satir okumak. Bu yaklasin sayesinde gigabyte'larca buyuklukte dosyalari bile sadece birkac megabyte bellek kullanarak isleyebilirsiniz. Benim tavsiyem, dosya boyutu 50 MB'i geciyor veya boyutu onceden bilinmiyorsa her zaman stream tabanli okuma kullanmaniz yonunde.

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

// readline ile satir satir okuma - en temiz yontem
async function satirSatirOku(dosyaYolu) {
    const dosyaStream = fs.createReadStream(dosyaYolu, {
        encoding: 'utf8',
        highWaterMark: 64 * 1024 // 64KB buffer
    });

    const rl = readline.createInterface({
        input: dosyaStream,
        crlfDelay: Infinity // Windows ve Unix satir sonlarini ayni isle
    });

    let satirNumarasi = 0;
    let toplam = 0;

    for await (const satir of rl) {
        satirNumarasi++;
        toplam += satir.length;

        // Her 10000 satirda bir ilerleme goster
        if (satirNumarasi % 10000 === 0) {
            const bellekMB = (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2);
            console.log(`${satirNumarasi} satir okundu... (Bellek: ${bellekMB} MB)`);
        }

        // Burada satirla istediginizi yapabilirsiniz
        // ornegin: veritabanina yazmak, filtrelemek, donusturmek
    }

    console.log(`\nToplam: ${satirNumarasi} satir, ${toplam} karakter`);
    return satirNumarasi;
}

// Dosyada arama yapma
async function dosyadaAra(dosyaYolu, aramaMetni) {
    const dosyaStream = fs.createReadStream(dosyaYolu, 'utf8');
    const rl = readline.createInterface({
        input: dosyaStream,
        crlfDelay: Infinity
    });

    const sonuclar = [];
    let satirNo = 0;

    for await (const satir of rl) {
        satirNo++;
        if (satir.includes(aramaMetni)) {
            sonuclar.push({ satirNo, icerik: satir.trim() });
        }
    }

    console.log(`"${aramaMetni}" icin ${sonuclar.length} sonuc bulundu:`);
    sonuclar.forEach(s => {
        console.log(`  Satir ${s.satirNo}: ${s.icerik.substring(0, 100)}`);
    });

    return sonuclar;
}

// Kullanim
async function main() {
    const logDosyasi = path.join(__dirname, 'buyuk-log.txt');

    // Ornek buyuk dosya olustur
    const yazStream = fs.createWriteStream(logDosyasi);
    for (let i = 0; i < 50000; i++) {
        yazStream.write(`[${new Date().toISOString()}] Satir ${i + 1}: Bu bir log mesajidir\n`);
    }
    yazStream.end();

    // Stream kapanana kadar bekle
    await new Promise(resolve => yazStream.on('finish', resolve));

    console.log('Dosya olusturuldu, okuma basliyor...\n');
    await satirSatirOku(logDosyasi);
}

main().catch(console.error);

CSV Dosyasi Isleme​


Buyuk CSV dosyalarini islemek gercek hayatta en sik karsilastigimiz senaryolardan biri. Ben e-ticaret projelerinde musteri verilerini, siparis kayitlarini falan CSV'den import ederken bu yontemi surekli kullaniyorum. Asagidaki ornekte bir CSV dosyasini satir satir okuyup parse ediyoruz. Ucuncu parti kutuphane kullanmadan basit bir CSV parser yaziyoruz cunku cogu zaman karmasik bir parser'a ihtiyac duymazsiniz.

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

// Basit CSV parser
function csvSatirParse(satir, ayirici = ',') {
    const degerler = [];
    let mevcut = '';
    let tirnaIcinde = false;

    for (let i = 0; i < satir.length; i++) {
        const karakter = satir[i];

        if (karakter === '"') {
            tirnaIcinde = !tirnaIcinde;
        } else if (karakter === ayirici && !tirnaIcinde) {
            degerler.push(mevcut.trim());
            mevcut = '';
        } else {
            mevcut += karakter;
        }
    }
    degerler.push(mevcut.trim());

    return degerler;
}

// Buyuk CSV dosyasini isle
async function csvIsle(dosyaYolu, isleyici) {
    const stream = fs.createReadStream(dosyaYolu, 'utf8');
    const rl = readline.createInterface({
        input: stream,
        crlfDelay: Infinity
    });

    let basliklar = null;
    let satirNo = 0;
    let islendiSayisi = 0;
    let hataSayisi = 0;

    for await (const satir of rl) {
        satirNo++;

        // Bos satirlari atla
        if (!satir.trim()) continue;

        // Ilk satir baslik
        if (!basliklar) {
            basliklar = csvSatirParse(satir);
            console.log('Basliklar:', basliklar.join(', '));
            continue;
        }

        try {
            const degerler = csvSatirParse(satir);
            const nesne = {};

            basliklar.forEach((baslik, index) => {
                nesne[baslik] = degerler[index] || '';
            });

            await isleyici(nesne, satirNo);
            islendiSayisi++;
        } catch (error) {
            hataSayisi++;
            console.error(`Satir ${satirNo} hatasi:`, error.message);
        }
    }

    console.log(`\nOzet: ${islendiSayisi} basarili, ${hataSayisi} hatali`);
}

// Kullanim ornegi
async function main() {
    const csvDosya = path.join(__dirname, 'urunler.csv');

    // Ornek CSV olustur
    const csvIcerik = `ad,fiyat,stok,kategori
"Laptop",15000,25,"Elektronik"
"Telefon",8000,50,"Elektronik"
"Masa",2000,15,"Mobilya"
"Sandalye",1500,30,"Mobilya"
"Kulaklik",500,100,"Aksesuar"`;

    fs.writeFileSync(csvDosya, csvIcerik);

    await csvIsle(csvDosya, (urun, satirNo) => {
        const fiyat = parseFloat(urun.fiyat);
        if (fiyat > 5000) {
            console.log(`  [Satir ${satirNo}] Pahali urun: ${urun.ad} - ${fiyat} TL`);
        }
    });
}

main().catch(console.error);

Transform Stream ile Isleme​


Daha ileri seviye bir yaklasim olarak Transform stream kullanabilirsiniz. Bu yaklasim ozellikle pipe zinciri kurmak istediginizde cok ise yarar. Bir dosyayi okur, donusturur ve baska bir dosyaya yazar. Tum bu islem bellek dostu bir sekilde gerceklesir cunku veriler kucuk parcalar halinde akar.

Tecrubeme gore buyuk dosyalarla calisirken en onemli sey bellek kullanimini izlemektir. process.memoryUsage() ile duzenli kontrol yapin ve bellek kullaniminin sabit kaldiginden emin olun. Eger surekli artiyorsa bir yerlerde veri biriktiriyorsunuz demektir. Backpressure mekanizmasini da goz ardi etmeyin, yoksa yazma hizi okuma hizini gecerse sorun yasarsiniz. Neyse, simdilik bu kadar. Bir sonraki konuda path modulunu inceleyecegiz!
 

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)

Geri
Üst