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!
[NODE JS] CSV Dosyasını Stream ile İşleme
CSV dosyaları, veri alışverişinin en yaygın formatlarından biridir. Excel'den dışa aktarılan veriler, veritabanı yedekleri, log kayıtları ve daha birçok veri kaynağı CSV formatında olabilir. Ben bir e-ticaret projesinde yüz binlerce ürün kaydını içeren CSV dosyalarıyla çalışmak zorunda kaldığımda, tüm dosyayı belleğe yüklemenin ne kadar tehlikeli olduğunu deneyimledim. 500 MB'lık bir CSV dosyasını fs.readFileSync ile okumaya çalıştığımda Node.js prosesi bellek yetersizliğinden çöktü. İşte bu noktada stream tabanlı CSV işleme kurtarıcı oldu.
Stream ile CSV işleme yaklaşımı, dosyayı satır satır okuyarak her satırı bağımsız olarak işlemenize olanak tanır. Bu sayede dosya boyutu ne olursa olsun bellek kullanımı sabit kalır. Gigabaytlarca büyüklükteki CSV dosyalarını bile birkaç megabayt bellekle işleyebilirsiniz.
Node.js'in dahili readline modülü, satır satır okuma işlemi için mükemmel bir araçtır. ReadStream ile birleştirildiğinde CSV dosyasının her satırını ayrı ayrı işleyebilirsiniz. Ancak burada bir uyarı vermem gerekiyor: CSV formatı göründüğü kadar basit değildir. Tırnak işaretleri içindeki virgüller, satır sonları ve kaçış karakterleri gibi edge case'ler vardır. Basit bir split(',') işlemi çoğu zaman yetersiz kalır.
Transform stream'ler, CSV işleme için çok güçlü bir araçtır. Gelen ham veriyi anlamlı JavaScript nesnelerine dönüştürebilirsiniz. Her CSV satırı bir objeye çevrilir ve bu objeler pipeline boyunca akar. Filtreleme, dönüştürme ve gruplama gibi işlemleri farklı transform katmanlarında gerçekleştirebilirsiniz.
Performans optimizasyonu açısından, CSV satırlarını tek tek veritabanına yazmak yerine toplu ekleme (batch insert) yaklaşımını kullanmanızı öneririm. Örneğin her 1000 satırda bir veritabanına toplu yazma işlemi yaparsanız hem I/O sayısını azaltırsınız hem de toplam işlem süresini önemli ölçüde kısaltırsınız. Bu tekniği stream'in data olayı içinde bir sayaç tutarak kolayca uygulayabilirsiniz.
Hata yönetimi de CSV işlemede kritik bir konudur. Bozuk satırlar, eksik sütunlar veya geçersiz karakter kodlamaları gibi sorunlarla karşılaşabilirsiniz. Bu tür hataları satır bazında yakalayıp loglayarak sorunlu satırları atlayabilir ve işlemi kesintisiz sürdürebilirsiniz. Bir hata yüzünden tüm işlemin durması genellikle kabul edilemez bir davranıştır.
Encoding konusu da özellikle Türkçe karakterler içeren CSV dosyalarında önemlidir. Windows'ta oluşturulan CSV dosyaları genellikle Windows-1254 veya ISO-8859-9 kodlamasında olur. Bu dosyaları UTF-8 olarak okumaya çalışırsanız Türkçe karakterler bozulur. İconv-lite gibi bir kütüphane kullanarak kodlama dönüşümü yapmanız gerekebilir.
JavaScript:
const fs = require('fs');
const readline = require('readline');
const { Transform, pipeline } = require('stream');
const path = require('path');
// Gelişmiş CSV satır ayrıştırıcı (tırnak içi virgülleri destekler)
function csvSatirAyristir(satir, ayrac = ',') {
const sonuc = [];
let mevcutDeger = '';
let tirnakIcinde = false;
for (let i = 0; i < satir.length; i++) {
const karakter = satir[i];
if (karakter === '"') {
if (tirnakIcinde && satir[i + 1] === '"') {
mevcutDeger += '"';
i++; // Çift tırnak kaçış karakterini atla
} else {
tirnakIcinde = !tirnakIcinde;
}
} else if (karakter === ayrac && !tirnakIcinde) {
sonuc.push(mevcutDeger.trim());
mevcutDeger = '';
} else {
mevcutDeger += karakter;
}
}
sonuc.push(mevcutDeger.trim());
return sonuc;
}
// CSV dosyasını stream ile okuyan sınıf
class CsvOkuyucu {
constructor(dosyaYolu, secenekler = {}) {
this.dosyaYolu = dosyaYolu;
this.ayrac = secenekler.ayrac || ',';
this.baslikSatiri = secenekler.baslikSatiri !== false;
this.kodlama = secenekler.kodlama || 'utf-8';
this.basliklar = [];
this.satirSayisi = 0;
this.hatalıSatirlar = [];
}
async isle(satirCallback, tamamCallback) {
return new Promise((resolve, reject) => {
const okumaStream = fs.createReadStream(this.dosyaYolu, {
encoding: this.kodlama,
highWaterMark: 64 * 1024 // 64KB parçalar halinde oku
});
const rl = readline.createInterface({
input: okumaStream,
crlfDelay: Infinity // Windows ve Unix satır sonlarını destekle
});
let ilkSatir = true;
rl.on('line', (satir) => {
// Boş satırları atla
if (satir.trim() === '') return;
try {
const degerler = csvSatirAyristir(satir, this.ayrac);
if (ilkSatir && this.baslikSatiri) {
this.basliklar = degerler;
ilkSatir = false;
return;
}
ilkSatir = false;
this.satirSayisi++;
// Başlıklar varsa obje oluştur, yoksa dizi döndür
if (this.basliklar.length > 0) {
const kayit = {};
this.basliklar.forEach((baslik, indeks) => {
kayit[baslik] = degerler[indeks] || '';
});
satirCallback(kayit, this.satirSayisi);
} else {
satirCallback(degerler, this.satirSayisi);
}
} catch (hata) {
this.hatalıSatirlar.push({
satirNo: this.satirSayisi + 1,
icerik: satir,
hata: hata.message
});
}
});
rl.on('close', () => {
const ozet = {
toplamSatir: this.satirSayisi,
hataliSatir: this.hatalıSatirlar.length,
basliklar: this.basliklar
};
console.log('
--- CSV İşleme Özeti ---');
console.log('Toplam işlenen satır: ' + ozet.toplamSatir);
console.log('Hatalı satır sayısı: ' + ozet.hataliSatir);
if (tamamCallback) tamamCallback(ozet);
resolve(ozet);
});
rl.on('error', reject);
okumaStream.on('error', reject);
});
}
}
// Toplu işlem ile veritabanı yazma simülasyonu
async function csvTopluIsle(dosyaYolu, grupBoyutu = 1000) {
const okuyucu = new CsvOkuyucu(dosyaYolu, { ayrac: ';' });
let tampon = [];
let toplamKaydedilen = 0;
await okuyucu.isle(
(kayit, satirNo) => {
tampon.push(kayit);
if (tampon.length >= grupBoyutu) {
// Toplu kaydetme işlemi (veritabanı simülasyonu)
console.log('Toplu kayıt: ' + tampon.length + ' satır işlendi (toplam: ' + satirNo + ')');
toplamKaydedilen += tampon.length;
tampon = [];
}
},
(ozet) => {
// Kalan kayıtları işle
if (tampon.length > 0) {
toplamKaydedilen += tampon.length;
console.log('Son grup: ' + tampon.length + ' satır kaydedildi');
}
console.log('Toplam kaydedilen: ' + toplamKaydedilen);
}
);
}
// Kullanım
const okuyucu = new CsvOkuyucu('./urunler.csv');
okuyucu.isle(
(urun, satirNo) => {
if (satirNo % 10000 === 0) {
console.log(satirNo + ' satır işlendi...');
}
}
).then(ozet => console.log('Bitti!', ozet));
CSV dosyalarını stream ile işlemek, büyük veri kümeleriyle çalışırken vazgeçilmez bir tekniktir. Satır satır okuma, toplu yazma ve hata yönetimi gibi stratejilerle milyonlarca satırlık dosyaları bile sorunsuz işleyebilirsiniz. Bu yaklaşım hem bellek dostu hem de ölçeklenebilir bir çözüm sunar.
Emeğiniz ve katkınız için teşekkür ederiz!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar!

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)
Benzer konular
- Cevaplar
- 1
- Görüntüleme
- 522
- Cevaplar
- 3
- Görüntüleme
- 1K
