Setelah Path merepresentasikan nama, class java.nio.file.Files mengambil alih pekerjaan beratnya. Semua method di Files bersifat static, menerima Path sebagai argumen, dan membungkus panggilan sistem operasi menjadi satu baris kode: memeriksa keberadaan, membaca seluruh isi, menyalin, memindahkan, hingga memproses berkas baris demi baris sebagai stream. Sejak Java 11 hadir pula readString dan writeString yang menyederhanakan kasus paling sering — berkas teks kecil. Pada Chapter ini kita menyusuri method yang paling sering terpakai, lengkap dengan pola penanganan exception yang menyertainya.

Operasi Berkas Sehari-hari #

Berbeda dari java.io.File yang mengembalikan boolean untuk segalanya, Files melempar IOException beserta subclass-nya ketika operasi gagal. Kegagalan pun menjadi informatif: NoSuchFileException membawa nama berkas, FileAlreadyExistsException memberi tahu target yang bentrok. Method menulis juga menerima varargs OpenOption seperti CREATE, APPEND, atau REPLACE_EXISTING — tanpa opsi, writeString mengganti isi berkas lama atau membuat berkas baru bila belum ada.

Program berikut merangkai delapan operasi umum terhadap berkas pendamping artikel.txt:

java TugasBerkas.java
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

public class TugasBerkas {
    public static void main(String[] args) throws IOException {
        Path artikel = Path.of("artikel.txt");

        System.out.println("exists        : " + Files.exists(artikel));
        System.out.println("size          : " + Files.size(artikel) + " byte");

        String isi = Files.readString(artikel, StandardCharsets.UTF_8);
        System.out.println("readString    : " + isi.lines().count() + " baris");
        System.out.println("kata pertama  : " + isi.split(" ")[0]);

        Path salinan = Path.of("salinan.txt");
        Files.copy(artikel, salinan, StandardCopyOption.REPLACE_EXISTING);
        System.out.println("copy          : ukuran sama = "
                + (Files.size(salinan) == Files.size(artikel)));

        Path arsip = Path.of("arsip.txt");
        Files.move(salinan, arsip, StandardCopyOption.REPLACE_EXISTING);
        System.out.println("move          : salinan ada = " + Files.exists(salinan)
                + ", arsip ada = " + Files.exists(arsip));

        long jumlahBaris;
        try (var stream = Files.lines(arsip, StandardCharsets.UTF_8)) {
            jumlahBaris = stream.count();
        }
        System.out.println("lines         : " + jumlahBaris + " baris");

        Path target = Path.of("catatan", "2026", "ringkasan.txt");
        Files.createDirectories(target.getParent());
        Files.writeString(target, "Diproses oleh Files.\n", StandardCharsets.UTF_8);
        try (BufferedReader pembaca = Files.newBufferedReader(target, StandardCharsets.UTF_8)) {
            System.out.println("newBufferedReader: " + pembaca.readLine());
        }

        System.out.println("delete        : " + Files.deleteIfExists(arsip));
        System.out.println("arsip ada     : " + Files.exists(arsip));
    }
}

Output yang Dihasilkan:

text
exists        : true
size          : 91 byte
readString    : 3 baris
kata pertama  : Belajar
copy          : ukuran sama = true
move          : salinan ada = false, arsip ada = true
lines         : 3 baris
newBufferedReader: Diproses oleh Files.
delete        : true
arsip ada     : false

Mari kita bedah operasi demi operasi:

  1. Baris 13-14 (exists, size): dua pertanyaan paling dasar. size() mengembalikan ukuran dalam byte dan melempar exception bila berkasnya tidak ada — berbeda dari File.length() yang mengembalikan 0 tanpa penjelasan.
  2. Baris 16-18 (readString): membaca seluruh berkas teks menjadi satu String. Charset UTF-8 selalu dinyatakan eksplisit agar hasilnya sama di semua mesin, bukan bergantung pada locale sistem operasi.
  3. Baris 21-23 (copy): menyalin dengan opsi REPLACE_EXISTING agar berkas salinan lama tertimpa; tanpa opsi itu, menimpa berkas yang sudah ada melempar FileAlreadyExistsException.
  4. Baris 26-28 (move): memindahkan atau mengganti nama. Setelah move berhasil, path sumber salinan.txt tidak lagi ada — keluaran memperlihatkan peralihan tersebut.
  5. Baris 31-34 (Files.lines dalam try-with-resources): menghasilkan Stream<String> yang dibuka malas (lazily); stream ini memegang pegangan berkas sehingga wajib ditutup, dan try-with-resources menutupnya otomatis.
  6. Baris 37-42 (createDirectories + writeString + newBufferedReader): membuat seluruh rantai folder catatan/2026 sekaligus, menulis satu baris, lalu membacanya kembali dengan BufferedReader — pola baca-tulis-tuntaskan.

Menangani Berkas yang Tidak Ada #

Ketika berkas hilang, Files tidak diam melainkan melempar NoSuchFileException, subclass dari IOException yang menyimpan nama berkas penyebab. Karena exception ini spesifik, blok catch bisa membedakan “berkas memang tidak ada” dari “ada tetapi tidak bisa dibaca”. Kasus kedua yang sering menjatuhkan pemula: menulis ke path bertingkat ketika folder induknya belum dibuat.

Program berikut mengalami kedua kejadian itu lalu pulih darinya:

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;

public class TanganiHilang {
    public static void main(String[] args) {
        Path konfigurasi = Path.of("konfigurasi.yaml");
        try {
            String isi = Files.readString(konfigurasi);
            System.out.println("terbaca: " + isi);
        } catch (NoSuchFileException e) {
            System.out.println("berkas tidak ada : " + e.getFile());
        } catch (IOException e) {
            System.out.println("I/O gagal         : " + e.getClass().getSimpleName());
        }

        Path target = Path.of("hasil", "laporan.txt");
        try {
            Files.writeString(target, "isi laporan", StandardCharsets.UTF_8);
            System.out.println("tulis langsung   : sukses");
        } catch (NoSuchFileException e) {
            System.out.println("tulis langsung   : gagal, induk belum ada");
        } catch (IOException e) {
            System.out.println("tulis langsung   : gagal, "
                    + e.getClass().getSimpleName());
        }

        try {
            Files.createDirectories(target.getParent());
            Files.writeString(target, "isi laporan", StandardCharsets.UTF_8);
            String hasil = Files.readString(target, StandardCharsets.UTF_8);
            System.out.println("setelah buat induk: " + hasil);
        } catch (IOException e) {
            System.out.println("gagal total: " + e.getClass().getSimpleName());
        }
    }
}

Output yang Dihasilkan:

text
berkas tidak ada : konfigurasi.yaml
tulis langsung   : gagal, induk belum ada
setelah buat induk: isi laporan

Urutan blok catch pada segmen pertama memegang peran penting: NoSuchFileException ditangkap lebih dulu karena class tersebut lebih spesifik, disusul IOException umum sebagai jaring pengaman — compiler Java menolak urutan terbalik karena subclass tidak akan pernah terjangkau. Segmen kedua membuktikan bahwa writeString ke hasil/laporan.txt gagal selama folder hasil belum dibuat, padahal exception-nya tetap NoSuchFileException. Setelah createDirectories(target.getParent()) menyiapkan induknya, penulisan yang sama berhasil dan isi terbaca kembali — pola gagal-kenali-perbaiki yang tuntas.

Sebagai peta ringkas, berikut method Files yang paling sering terpakai:

KebutuhanMethodCatatan
Periksaexists, size, isRegularFiletanpa exception
Baca teksreadString, lines, newBufferedReadersebutkan charset
Tulis tekswriteString, newBufferedWriteropsi APPEND, CREATE
Salin / pindahcopy, moveREPLACE_EXISTING menimpa
Hapusdelete, deleteIfExistsfolder harus kosong
StrukturcreateDirectoriesbuat seluruh rantai induk

Di balik method singkat ini, Files tetap membuka stream byte dan karakter seperti biasa. Chapter berikutnya membuka selubung itu: kita akan bekerja langsung dengan InputStream dan OutputStream untuk memproses data biner mentah byte demi byte.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

TanganiHilang.java

Unduh berkas
java
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;

public class TanganiHilang {
    public static void main(String[] args) {
        Path konfigurasi = Path.of("konfigurasi.yaml");
        try {
            String isi = Files.readString(konfigurasi);
            System.out.println("terbaca: " + isi);
        } catch (NoSuchFileException e) {
            System.out.println("berkas tidak ada : " + e.getFile());
        } catch (IOException e) {
            System.out.println("I/O gagal         : " + e.getClass().getSimpleName());
        }

        Path target = Path.of("hasil", "laporan.txt");
        try {
            Files.writeString(target, "isi laporan", StandardCharsets.UTF_8);
            System.out.println("tulis langsung   : sukses");
        } catch (NoSuchFileException e) {
            System.out.println("tulis langsung   : gagal, induk belum ada");
        } catch (IOException e) {
            System.out.println("tulis langsung   : gagal, "
                    + e.getClass().getSimpleName());
        }

        try {
            Files.createDirectories(target.getParent());
            Files.writeString(target, "isi laporan", StandardCharsets.UTF_8);
            String hasil = Files.readString(target, StandardCharsets.UTF_8);
            System.out.println("setelah buat induk: " + hasil);
        } catch (IOException e) {
            System.out.println("gagal total: " + e.getClass().getSimpleName());
        }
    }
}

TugasBerkas.java

Unduh berkas
java
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

public class TugasBerkas {
    public static void main(String[] args) throws IOException {
        Path artikel = Path.of("artikel.txt");

        System.out.println("exists        : " + Files.exists(artikel));
        System.out.println("size          : " + Files.size(artikel) + " byte");

        String isi = Files.readString(artikel, StandardCharsets.UTF_8);
        System.out.println("readString    : " + isi.lines().count() + " baris");
        System.out.println("kata pertama  : " + isi.split(" ")[0]);

        Path salinan = Path.of("salinan.txt");
        Files.copy(artikel, salinan, StandardCopyOption.REPLACE_EXISTING);
        System.out.println("copy          : ukuran sama = "
                + (Files.size(salinan) == Files.size(artikel)));

        Path arsip = Path.of("arsip.txt");
        Files.move(salinan, arsip, StandardCopyOption.REPLACE_EXISTING);
        System.out.println("move          : salinan ada = " + Files.exists(salinan)
                + ", arsip ada = " + Files.exists(arsip));

        long jumlahBaris;
        try (var stream = Files.lines(arsip, StandardCharsets.UTF_8)) {
            jumlahBaris = stream.count();
        }
        System.out.println("lines         : " + jumlahBaris + " baris");

        Path target = Path.of("catatan", "2026", "ringkasan.txt");
        Files.createDirectories(target.getParent());
        Files.writeString(target, "Diproses oleh Files.\n", StandardCharsets.UTF_8);
        try (BufferedReader pembaca = Files.newBufferedReader(target, StandardCharsets.UTF_8)) {
            System.out.println("newBufferedReader: " + pembaca.readLine());
        }

        System.out.println("delete        : " + Files.deleteIfExists(arsip));
        System.out.println("arsip ada     : " + Files.exists(arsip));
    }
}