0Pricing
Java Academy · Pelajaran

WatchService: Memantau Perubahan File

Daftarkan WatchService untuk mendeteksi pembuatan, perubahan, dan penghapusan file secara waktu nyata.

WatchService: Memantau Perubahan File adalah pelajaran Java Academy gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Java Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Java Academy mencakup 4 pelajaran total.

Apa Itu WatchService?

WatchService memantau direktori untuk mendeteksi peristiwa sistem berkas: pembuatan, perubahan, dan penghapusan. Fitur ini menggunakan notifikasi tingkat OS (inotify di Linux, FSEvents di macOS)—jauh lebih efisien daripada pemeriksaan berkala.

import java.nio.file.*;

WatchService watcher = FileSystems.getDefault().newWatchService();
Path dir = Path.of("/home/user/watched");

dir.register(watcher,
    StandardWatchEventKinds.ENTRY_CREATE,
    StandardWatchEventKinds.ENTRY_MODIFY,
    StandardWatchEventKinds.ENTRY_DELETE
);
System.out.println("Watching: " + dir);

Memeriksa Peristiwa secara Berkala

Panggil watcher.take() untuk memblokir hingga suatu peristiwa terjadi, lalu proses peristiwa tersebut:

while (true) {
    WatchKey key;
    try {
        key = watcher.take(); // blocks until events arrive
    } catch (InterruptedException e) {
        break;
    }
    
    for (WatchEvent<?> event : key.pollEvents()) {
        WatchEvent.Kind<?> kind = event.kind();
        Path changed = ((WatchEvent<Path>) event).context();
        System.out.println(kind.name() + ": " + changed);
    }
    
    key.reset(); // must reset to receive further events
}

Pemeriksaan Berkala Tanpa Pemblokiran

Gunakan watcher.poll() untuk pemeriksaan tanpa pemblokiran, atau poll(timeout, unit) untuk menunggu selama waktu tertentu:

// Non-blocking — returns null if no events
WatchKey key = watcher.poll();
if (key != null) {
    // process events
    key.reset();
}

// Wait up to 5 seconds:
WatchKey key2 = watcher.poll(5, java.util.concurrent.TimeUnit.SECONDS);
if (key2 != null) {
    // process events
    key2.reset();
}

Peristiwa OVERFLOW

Jika peristiwa terakumulasi lebih cepat daripada kemampuan aplikasi memprosesnya, peristiwa OVERFLOW menandakan bahwa beberapa peristiwa telah hilang. Tangani kondisi ini dengan baik:

for (WatchEvent<?> event : key.pollEvents()) {
    if (event.kind() == StandardWatchEventKinds.OVERFLOW) {
        System.out.println("OVERFLOW: some events missed, rescanning directory");
        // rescan dir to find current state
        continue;
    }
    // process normal events
}

Contoh Lengkap yang Berfungsi

Pemantau berkas lengkap yang berjalan pada utas latar belakang:

class FileWatcher implements Runnable {
    private final WatchService watcher;
    
    FileWatcher(Path dir) throws IOException {
        watcher = FileSystems.getDefault().newWatchService();
        dir.register(watcher,
            StandardWatchEventKinds.ENTRY_CREATE,
            StandardWatchEventKinds.ENTRY_MODIFY,
            StandardWatchEventKinds.ENTRY_DELETE);
    }
    
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                WatchKey key = watcher.take();
                for (WatchEvent<?> e : key.pollEvents())
                    System.out.println(e.kind() + ": " + e.context());
                key.reset();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

Memantau Beberapa Direktori

Daftarkan beberapa direktori dengan WatchService yang sama. Gunakan WatchKey yang dikembalikan untuk mengidentifikasi direktori asal peristiwa:

Map<WatchKey, Path> keyMap = new HashMap<>();

for (Path dir : List.of(Path.of("/logs"), Path.of("/config"))) {
    WatchKey key = dir.register(watcher,
        StandardWatchEventKinds.ENTRY_MODIFY);
    keyMap.put(key, dir);
}

WatchKey key = watcher.take();
Path dir = keyMap.get(key);
System.out.println("Changed in: " + dir);

Menyelesaikan Jalur Lengkap

context() pada peristiwa hanya mengembalikan nama berkas, bukan jalur lengkap. Selesaikan jalur tersebut berdasarkan direktori yang dipantau:

WatchEvent<Path> pathEvent = (WatchEvent<Path>) event;
Path filename = pathEvent.context();
Path fullPath = watchedDir.resolve(filename);
System.out.println("Full path: " + fullPath);

Pemantauan Direktori secara Rekursif

WatchService hanya memantau direktori yang didaftarkan, bukan subdirektorinya. Untuk pemantauan rekursif, telusuri pohon direktori dan daftarkan setiap subdirektori:

WatchService watcher = FileSystems.getDefault().newWatchService();
Path root = Path.of("/project");

try (var stream = Files.walk(root)) {
    stream.filter(Files::isDirectory)
          .forEach(dir -> {
              try { dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE,
                  StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
              } catch (IOException e) { throw new RuntimeException(e); }
          });
}

Pembersihan Sumber Daya

Selalu tutup WatchService setelah selesai untuk membebaskan sumber daya OS:

try (WatchService watcher = FileSystems.getDefault().newWatchService()) {
    Path dir = Path.of("/tmp/watch");
    dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
    
    WatchKey key = watcher.poll(10, java.util.concurrent.TimeUnit.SECONDS);
    if (key != null) {
        key.pollEvents().forEach(e -> System.out.println(e.context()));
        key.reset();
    }
} // watcher.close() called automatically

Kasus Penggunaan Praktis: Muat Ulang Konfigurasi

Gunakan WatchService untuk memuat ulang konfigurasi saat berkas berubah:

class ConfigWatcher {
    private volatile Map<String, String> config = new HashMap<>();
    
    void loadConfig(Path file) throws IOException {
        config = Files.readAllLines(file).stream()
            .filter(l -> l.contains("="))
            .collect(Collectors.toMap(
                l -> l.split("=")[0].trim(),
                l -> l.split("=")[1].trim(),
                (a,b) -> b
            ));
    }
    
    // Call loadConfig again on ENTRY_MODIFY event
}

Keterbatasan WatchService

Keterbatasan penting:

  • Hanya memantau direktori, bukan berkas individual
  • Tidak rekursif secara bawaan—daftarkan setiap subdirektori secara manual
  • Di macOS: secara internal menggunakan pemeriksaan berkala (kurang responsif daripada inotify di Linux)
  • Dapat melewatkan perubahan yang terjadi secara cepat dan bertubi-tubi (OVERFLOW)
  • WatchKey menjadi tidak valid jika direktori yang dipantau dihapus

Pemeriksaan Singkat

Setelah memproses peristiwa dari WatchKey, apa yang harus Anda panggil sebelum WatchService mengirimkan peristiwa berikutnya untuk kunci tersebut?

Ringkasan: WatchService

Inti penting:

  • Daftarkan direktori dengan peristiwa ENTRY_CREATE/MODIFY/DELETE
  • take() memblokir; poll() tidak memblokir; gunakan poll(timeout, unit) untuk menunggu selama waktu tertentu
  • Selalu panggil key.reset() setelah memproses peristiwa
  • context() hanya mengembalikan nama berkas—selesaikan berdasarkan direktori yang dipantau untuk mendapatkan jalur lengkap
  • Tutup WatchService dengan try-with-resources
  • Pemantauan rekursif memerlukan pendaftaran setiap subdirektori

Pertanyaan yang Sering Diajukan

Apakah pelajaran “WatchService: Memantau Perubahan File” gratis?

Ya — teks lengkap “WatchService: Memantau Perubahan File” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Java Academy, upgrade ke CoddyKit PRO. Kursus Java Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “WatchService: Memantau Perubahan File”?

Daftarkan WatchService untuk mendeteksi pembuatan, perubahan, dan penghapusan file secara waktu nyata. Kamu berlatih Java Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Java Academy?

Tidak diperlukan pengalaman sebelumnya. Java Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.

Berapa lama pelajaran “WatchService: Memantau Perubahan File” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Java Academy ini?

Ya. Setiap pelajaran Java Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Path: Merepresentasikan Lokasi File
  2. Utilitas Files: Membaca, Menulis, Menyalin, Memindahkan
  3. Menelusuri Pohon Direktori dengan Files.walk
  4. WatchService: Memantau Perubahan File
← Kembali ke Java Academy