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] fs.watch ile Dosya Degisikligi Izleme

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] fs.watch ile Dosya Degisikligi Izleme​


Merhaba arkadaslar, bugun sizinle Node.js'in belki de en az konusulan ama bir o kadar da ise yarayan ozelliklerinden biri olan fs.watch fonksiyonunu konusacagiz. Ben bunu ilk kez bir projede hot-reload mekanizmasi kurarken kesfettim ve o gundan beri bir cok farkli senaryoda kullandim. Ozellikle dosya degisikliklerini anlik olarak takip etmek istediginiz durumlarda inanilmaz pratik bir cozum sunuyor.

fs.watch Nedir ve Neden Kullanilir?​


fs.watch, Node.js'in yerlesik fs modulunde bulunan ve dosya sistemindeki degisiklikleri izlemenizi saglayan bir fonksiyondur. Bir dosya veya klasor uzerinde degisiklik oldugunda sizi bilgilendiren bir watcher olusturur. Ben genelde bunu config dosyalarinin degisimini takip etmek, log dosyalarini canli izlemek veya gelistirme ortaminda otomatik yeniden yukleme yapmak icin kullaniyorum.

Isletim sistemi seviyesinde calisan bu fonksiyon, dosya sisteminin native event mekanizmasini kullanir. Yani surekli dosyayi okuyup kontrol etmez, isletim sistemi bir degisiklik oldugunda Node.js'e haber verir. Bu da performans acisindan buyuk bir avantaj saglar. Ha bu arada, buna "polling" yerine "event-driven" yaklasim deniyor.

Temel Kullanim​


En basit haliyle fs.watch su sekilde calisir: bir dosya yolu verirsiniz, bir callback fonksiyonu tanimlarsiniz ve dosyada her degisiklik oldugunda bu callback tetiklenir. Callback fonksiyonu iki parametre alir: eventType ve filename. eventType ya "rename" ya da "change" olabilir. rename dosyanin adi degistiginde veya silindigi/olusturuldugu zaman, change ise icerik degistiginde tetiklenir.

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

// Tek bir dosyayi izleme
const dosyaYolu = path.join(__dirname, 'config.json');

console.log('Dosya izleme baslatildi...');
console.log('Izlenen dosya:', dosyaYolu);

const watcher = fs.watch(dosyaYolu, (eventType, filename) => {
    const simdi = new Date().toLocaleTimeString('tr-TR');

    if (eventType === 'change') {
        console.log(`[${simdi}] Dosya degisti: ${filename}`);

        // Degisen dosyanin icerigini okuyalim
        fs.readFile(dosyaYolu, 'utf8', (err, data) => {
            if (err) {
                console.error('Dosya okunamadi:', err.message);
                return;
            }
            try {
                const config = JSON.parse(data);
                console.log('Yeni config degerleri:', config);
            } catch (parseErr) {
                console.error('JSON parse hatasi:', parseErr.message);
            }
        });
    } else if (eventType === 'rename') {
        console.log(`[${simdi}] Dosya yeniden adlandirildi veya silindi: ${filename}`);
    }
});

watcher.on('error', (error) => {
    console.error('Watcher hatasi:', error.message);
});

// Programi durdurmak icin
process.on('SIGINT', () => {
    console.log('\nIzleme durduruluyor...');
    watcher.close();
    process.exit(0);
});

Klasor Izleme ve Recursive Secenegi​


Benim en cok kullandigim senaryo aslinda tek bir dosya degil, bir klasorun tamamini izlemek. Mesela src klasorunuzdeki tum dosyalari izleyip degisiklik oldugunda bir build islemi baslatmak isteyebilirsiniz. Bunun icin recursive secenegini kullanabilirsiniz ama dikkat edin, bu secenek her platformda ayni sekilde calismayabiliyor. macOS ve Windows'ta sorunsuz calisir ama Linux'ta recursive destegi sinirlidir.

Tecrubeme gore Linux ortaminda recursive izleme yapacaksaniz, chokidar gibi bir kutuphane kullanmanizi tavsiye ederim. Ama Windows veya macOS'ta calisiyorsaniz native fs.watch gayet yeterli olacaktir.

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

// Klasoru recursive olarak izleme
const klasorYolu = path.join(__dirname, 'src');

const watchOptions = {
    recursive: true,    // Alt klasorleri de izle
    persistent: true,   // Process'i ayakta tut
    encoding: 'utf8'    // Dosya adi encoding'i
};

console.log('Klasor izleme baslatildi:', klasorYolu);

const watcher = fs.watch(klasorYolu, watchOptions, (eventType, filename) => {
    if (!filename) return; // Bazi sistemlerde filename null gelebilir

    const tamYol = path.join(klasorYolu, filename);
    const uzanti = path.extname(filename).toLowerCase();

    // Sadece belirli dosya turlerini izle
    const izlenecekUzantilar = ['.js', '.ts', '.json', '.css'];

    if (!izlenecekUzantilar.includes(uzanti)) {
        return; // Bu uzantiyi umursamiyoruz
    }

    console.log(`\n=== Degisiklik Algilandi ===`);
    console.log(`Tur: ${eventType}`);
    console.log(`Dosya: ${filename}`);
    console.log(`Tam Yol: ${tamYol}`);
    console.log(`Zaman: ${new Date().toLocaleString('tr-TR')}`);

    // Dosya var mi kontrol et (rename event'inde silinmis olabilir)
    fs.access(tamYol, fs.constants.F_OK, (err) => {
        if (err) {
            console.log('Dosya silindi veya tasindi.');
        } else {
            console.log('Dosya guncellendi.');
            // Burada build, lint veya test calistirabilirsiniz
        }
    });
});

watcher.on('error', (err) => {
    console.error('Izleme hatasi:', err);
});

console.log('Degisiklikleri izliyorum... (Ctrl+C ile durdurabilirsiniz)');

Debounce ile Tekrarlanan Event'leri Onleme​


fs.watch ile calisirken karsilasacaginiz en buyuk sorunlardan biri, tek bir dosya kaydinda birden fazla event tetiklenmesidir. Bu isletim sistemi seviyesinde olan bir sey ve bunu engelleyemezsiniz. Ama debounce mekanizmasiyla bu sorunu kolayca cozebilirsiniz. Benim tavsiyem, 100-200ms'lik bir debounce suresi koymak. Bu sure icinde gelen tum event'leri tek bir event olarak degerlendirirsiniz.

Ben production ortaminda bu pattern'i kullanmadan once cok basim agridi. Bir dosya kaydedildiginde bazen 3-4 kez event geliyordu ve her seferinde build islemi baslatiliyordu. Debounce ekledikten sonra bu sorun tamamen ortadan kalkti.

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

// Debounce mekanizmasi ile dosya izleme
class DosyaIzleyici {
    constructor(hedefYol, options = {}) {
        this.hedefYol = hedefYol;
        this.debounceMs = options.debounceMs || 150;
        this.zamanlayicilar = new Map();
        this.watcher = null;
        this.degisiklikSayaci = 0;
    }

    baslat() {
        this.watcher = fs.watch(
            this.hedefYol,
            { recursive: true },
            (eventType, filename) => {
                this._debounceHandler(eventType, filename);
            }
        );

        this.watcher.on('error', (err) => {
            console.error('Watcher hatasi:', err.message);
            this.yenidenBaslat();
        });

        console.log(`Izleme baslatildi: ${this.hedefYol}`);
    }

    _debounceHandler(eventType, filename) {
        if (!filename) return;

        const anahtar = `${eventType}-${filename}`;

        if (this.zamanlayicilar.has(anahtar)) {
            clearTimeout(this.zamanlayicilar.get(anahtar));
        }

        const zamanlayici = setTimeout(() => {
            this.zamanlayicilar.delete(anahtar);
            this.degisiklikSayaci++;
            this._degisiklikIsle(eventType, filename);
        }, this.debounceMs);

        this.zamanlayicilar.set(anahtar, zamanlayici);
    }

    _degisiklikIsle(eventType, filename) {
        console.log(`[#${this.degisiklikSayaci}] ${eventType}: ${filename}`);
    }

    durdur() {
        if (this.watcher) {
            this.watcher.close();
            this.zamanlayicilar.forEach(t => clearTimeout(t));
            this.zamanlayicilar.clear();
            console.log('Izleme durduruldu.');
        }
    }

    yenidenBaslat() {
        console.log('Izleme yeniden baslatiliyor...');
        this.durdur();
        setTimeout(() => this.baslat(), 1000);
    }
}

// Kullanim
const izleyici = new DosyaIzleyici(path.join(__dirname, 'src'), {
    debounceMs: 200
});

izleyici.baslat();

process.on('SIGINT', () => {
    izleyici.durdur();
    process.exit(0);
});

Dikkat Edilmesi Gerekenler​


fs.watch kullanirken birkac onemli noktaya dikkat etmeniz gerekiyor. Birincisi, farkli isletim sistemlerinde farkli davranabilir. Linux'ta inotify, macOS'ta FSEvents ve Windows'ta ReadDirectoryChangesW kullaniyor. Bu yuzden cross-platform bir uygulama gelistiriyorsaniz, her platformda test etmeyi ihmal etmeyin.

Ikincisi, cok fazla dosya izlediginizde sistem kaynaklarini tuketebilirsiniz. Linux'ta varsayilan inotify limiti genelde 8192 civarindadir. Bunu asarsaniz ENOSPC hatasi alirsiniz. Bu durumda ya limiti artirmaniz ya da izlediginiz dosya sayisini azaltmaniz gerekir.

Son olarak, watcher'i kullanmayi bitirdiginizde mutlaka close() metoduyla kapatmayi unutmayin. Aksi takdirde memory leak olusabilir ve uygulamaniz zamanla yavaslar. Benim basima gelmisti, saatlerce neden memory leak oldugunu aradim, sonunda kapanmayan watcher'larin oldugunu fark ettim. O gunden beri watcher'lari her zaman try-finally blogu icinde kullaniyorum. Neyse, bu kadar. Bir sonraki konuda gorusuruz!
 

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

Geri
Üst