mannaxxx 1
mannaxxx
Agora Metin2 1
Agora Metin2
[DEV]AB 1
[DEV]AB
Sevdamsın 1
Sevdamsın
TuZaKK 1
TuZaKK
kaptanmikro1 1
kaptanmikro1
farkmt2official 2
farkmt2official
kralhakan2009 1
kralhakan2009
Vahsi Uzman 1
Vahsi Uzman
Bvural41 1
Bvural41
Hikaye Ekle

[NODE JS] Zlib ile Sıkıştırılmış Dosya Açma

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] Zlib ile Sıkıştırılmış Dosya Açma​


Bir önceki konuda dosyaları gzip ile nasıl sıkıştıracağımızı öğrendik. Şimdi ise sıkıştırılmış dosyaları açma işlemine bakacağız. Bu iki konu birbirini tamamlayan ikiz kardeşler gibidir; birini bilip diğerini bilmemek eksik kalır. Ben bir keresinde bir müşterinin sunucusundaki yedek dosyalarını açmam gerektiğinde bu bilgiye ihtiyaç duymuştum. Sunucuda yüzlerce .gz dosyası vardı ve bunların içeriğine erişmem gerekiyordu.

Sıkıştırılmış dosyayı açma işlemi, sıkıştırma işleminin tam tersidir. Gzip formatında sıkıştırılmış bir dosyayı okursunuz, zlib modülünün gunzip fonksiyonundan geçirirsiniz ve orijinal veriyi elde edersiniz. Node.js'in zlib modülü bu işlem için createGunzip ve createUnzip gibi metodlar sunar.

Dosya açma işleminde dikkat edilmesi gereken en önemli konu, açılacak dosyanın gerçekten gzip formatında olup olmadığını kontrol etmektir. Gzip dosyalarının ilk iki byte'ı her zaman 0x1f ve 0x8b değerleridir. Bu magic bytes kontrolü yaparak yanlışlıkla gzip olmayan bir dosyayı açmaya çalışmanın önüne geçebilirsiniz. Bu kontrol olmadan işlem yaparsanız zlib modülü bir hata fırlatır ama bu hatayı önceden yakalayarak daha anlaşılır bir hata mesajı verebilirsiniz.

Stream tabanlı açma işlemi de sıkıştırma gibi pipe mekanizmasıyla çalışır. Sıkıştırılmış dosyadan okunan veriler parça parça açılır ve hedef dosyaya yazılır. Bu yaklaşım büyük dosyalarda bellek sorunlarını önler. Özellikle sunucu tarafında birden fazla istemcinin aynı anda dosya açma isteklerini işlemeniz gerektiğinde stream yaklaşımı olmazsa olmazdır.

Bir diğer yaygın senaryo, HTTP yanıtlarındaki gzip sıkıştırmasını açmaktır. Birçok web sunucusu yanıtlarını gzip ile sıkıştırarak gönderir. İstemci tarafında bu yanıtları açmanız gerekir. Node.js'in http modülüyle birlikte zlib kullanarak bu işlemi kolayca gerçekleştirebilirsiniz. Content-Encoding başlığını kontrol ederek yanıtın sıkıştırılmış olup olmadığını anlarsınız.

Hata yönetimi konusunda, bozuk sıkıştırılmış dosyalarla karşılaşma ihtimaliniz her zaman vardır. Ağ üzerinden aktarım sırasında veri kaybı olabilir, disk hataları dosyayı bozabilir veya sıkıştırma işlemi yarıda kalmış olabilir. Bu durumları zarif bir şekilde ele almanız ve kullanıcıya anlamlı geri bildirimler vermeniz gerekir.

Performans açısından, açma işlemi genellikle sıkıştırmadan daha hızlıdır. Sıkıştırma algoritmalarının doğası gereği veriyi analiz edip en uygun sıkıştırma yöntemini bulmak, sıkıştırılmış veriyi çözmekten daha fazla hesaplama gerektirir. Bu nedenle açma işlemlerinde CPU darboğazı yaşamanız daha düşük bir olasılıktır. Yine de çok sayıda eşzamanlı açma işlemi yapıyorsanız worker thread'ler kullanmayı düşünebilirsiniz.

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

// Gzip dosyası kontrolü - magic bytes doğrulaması
function gzipDosyasiMi(dosyaYolu) {
  try {
    const tampon = Buffer.alloc(2);
    const fd = fs.openSync(dosyaYolu, 'r');
    fs.readSync(fd, tampon, 0, 2, 0);
    fs.closeSync(fd);
    // Gzip magic bytes: 0x1f 0x8b
    return tampon[0] === 0x1f && tampon[1] === 0x8b;
  } catch (hata) {
    console.error('Dosya okuma hatası:', hata.message);
    return false;
  }
}

// Stream tabanlı dosya açma fonksiyonu
function dosyaAc(kaynakYol, hedefYol) {
  return new Promise((resolve, reject) => {
    // Önce gzip formatı kontrolü yap
    if (!gzipDosyasiMi(kaynakYol)) {
      reject(new Error('Bu dosya geçerli bir gzip dosyası değil: ' + kaynakYol));
      return;
    }

    const okumaStream = fs.createReadStream(kaynakYol);
    const yazmaStream = fs.createWriteStream(hedefYol);
    const gunzip = zlib.createGunzip();

    const dosyaBoyutu = fs.statSync(kaynakYol).size;
    let okunanBoyut = 0;

    okumaStream.on('data', (parca) => {
      okunanBoyut += parca.length;
      const yuzde = ((okunanBoyut / dosyaBoyutu) * 100).toFixed(1);
      process.stdout.write('
Açma ilerlemesi: %' + yuzde);
    });

    okumaStream.on('error', (hata) => {
      console.error('
Dosya okuma hatası:', hata.message);
      reject(hata);
    });

    gunzip.on('error', (hata) => {
      console.error('
Sıkıştırma açma hatası:', hata.message);
      // Bozuk dosya durumunda hedef dosyayı temizle
      yazmaStream.end();
      if (fs.existsSync(hedefYol)) {
        fs.unlinkSync(hedefYol);
        console.log('Bozuk çıktı dosyası silindi.');
      }
      reject(hata);
    });

    yazmaStream.on('error', (hata) => {
      console.error('
Yazma hatası:', hata.message);
      reject(hata);
    });

    yazmaStream.on('finish', () => {
      const sikistirilmisBoyut = dosyaBoyutu;
      const acilmisBoyut = fs.statSync(hedefYol).size;
      console.log('
--- Açma İşlemi Tamamlandı ---');
      console.log('Sıkıştırılmış boyut: ' + (sikistirilmisBoyut / 1024).toFixed(2) + ' KB');
      console.log('Açılmış boyut: ' + (acilmisBoyut / 1024).toFixed(2) + ' KB');
      resolve({ sikistirilmisBoyut, acilmisBoyut });
    });

    // Pipe zinciri: oku → aç → yaz
    okumaStream.pipe(gunzip).pipe(yazmaStream);
  });
}

// Bellekte doğrudan veri açma (küçük veriler için)
function veriAc(sikistirilmisBuffer) {
  return new Promise((resolve, reject) => {
    zlib.gunzip(sikistirilmisBuffer, (hata, sonuc) => {
      if (hata) {
        reject(new Error('Veri açılamadı: ' + hata.message));
        return;
      }
      console.log('Sıkıştırılmış veri: ' + sikistirilmisBuffer.length + ' byte');
      console.log('Açılmış veri: ' + sonuc.length + ' byte');
      resolve(sonuc);
    });
  });
}

// Toplu dosya açma işlemi
async function topluDosyaAc(gzDosyalari, hedefKlasor) {
  console.log('Toplu açma işlemi başlatılıyor...');

  if (!fs.existsSync(hedefKlasor)) {
    fs.mkdirSync(hedefKlasor, { recursive: true });
  }

  const sonuclar = [];

  for (const dosya of gzDosyalari) {
    const dosyaAdi = path.basename(dosya, '.gz');
    const hedefYol = path.join(hedefKlasor, dosyaAdi);

    console.log('
Açılıyor: ' + path.basename(dosya));

    try {
      const sonuc = await dosyaAc(dosya, hedefYol);
      sonuclar.push({ dosya: path.basename(dosya), basarili: true, ...sonuc });
    } catch (hata) {
      sonuclar.push({ dosya: path.basename(dosya), basarili: false, hata: hata.message });
    }
  }

  // Sonuç özeti
  console.log('
====== AÇMA RAPORU ======');
  sonuclar.forEach(s => {
    const durum = s.basarili ? '✓' : '✗';
    const detay = s.basarili
      ? (s.acilmisBoyut / 1024).toFixed(2) + ' KB'
      : 'Hata: ' + s.hata;
    console.log('  ' + durum + ' ' + s.dosya + ' → ' + detay);
  });

  return sonuclar;
}

// HTTP yanıtından gzip açma örneği
const http = require('http');

function gzipYanitOku(url) {
  return new Promise((resolve, reject) => {
    http.get(url, { headers: { 'Accept-Encoding': 'gzip' } }, (yanit) => {
      const kodlama = yanit.headers['content-encoding'];
      let veriStream = yanit;

      if (kodlama === 'gzip') {
        veriStream = yanit.pipe(zlib.createGunzip());
        console.log('Yanıt gzip ile sıkıştırılmış, açılıyor...');
      }

      const parcalar = [];
      veriStream.on('data', (parca) => parcalar.push(parca));
      veriStream.on('end', () => {
        const tamVeri = Buffer.concat(parcalar).toString('utf-8');
        resolve(tamVeri);
      });
      veriStream.on('error', reject);
    }).on('error', reject);
  });
}

// Ana çalıştırma fonksiyonu
async function main() {
  try {
    await dosyaAc('./yedek-veri.txt.gz', './yedek-veri.txt');
    console.log('Dosya başarıyla açıldı!');
  } catch (hata) {
    console.error('İşlem başarısız:', hata.message);
  }
}

main().catch(console.error);

Sıkıştırılmış dosya açma işlemi, veri yedekleme ve kurtarma senaryolarının vazgeçilmez bir parçasıdır. Magic bytes kontrolü, stream tabanlı yaklaşım ve kapsamlı hata yönetimi ile güvenilir bir açma sistemi kurabilirsiniz. Bir sonraki konuda CSV dosyalarını stream ile işlemeyi ele alacağız.
 

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

Geri
Üst