Sejak Java 7, penanganan berkas di Java berpusat pada dua kelas paket java.nio.file, yaitu Path yang menunjuk lokasi dan Files yang menjalankan operasinya. Topik ini membiasakan keduanya sebagai cara modern bekerja dengan berkas, menggantikan kelas java.io.File yang lebih tua. Setelah menelusurinya, pembuatan folder, penulisan berkas, penyalinan, pemindahan, penghapusan, dan penelusuran isi folder dapat ditulis dalam beberapa baris kode yang mudah dibaca.
Path sebagai penunjuk lokasi#
Path adalah representasi jalur berkas pada sistem berkas. Objeknya tidak menyentuh berkas apa pun dan tidak memeriksa keberadaan lokasinya, sehingga Path menuju folder yang belum ada tetap sah dibuat. Jalurnya bisa relatif terhadap folder kerja program atau absolut sejak dari akar sistem. Pabrik Path.of(...) menerima satu jalur utuh atau beberapa potongan nama yang digabung dengan pemisah sesuai sistem operasi, dan metode-metodenya murni mengolah teks jalur tanpa efek samping.
Jalur yang sama ditulis dengan pemisah berbeda di tiap sistem operasi, yaitu tanda garis miring pada Linux dan macOS serta tanda garis miring terbalik pada Windows. Kelas Path menyerahkan urusan itu pada pabriknya, sehingga kode yang sama berjalan di keduanya tanpa penggabungan string manual. Objek Path juga bersifat imutabel, yakni setiap metode seperti resolve dan normalize mengembalikan objek baru, sedangkan jalur lama tidak pernah berubah. Kelas lama yang digantikannya, java.io.File, masih banyak ditemui pada kode lama, dan objek File memiliki metode toPath() untuk berpindah ke API baru ini.
import java.nio.file.Path;
public class DemoPath {
public static void main(String[] args) {
Path relatif = Path.of("arsip", "2026", "catatan.txt");
Path absolut = Path.of("/home/budi/arsip/catatan.txt");
System.out.println("Path : " + relatif);
System.out.println("Nama berkas : " + relatif.getFileName());
System.out.println("Folder induk : " + relatif.getParent());
System.out.println("Jumlah elemen nama : " + relatif.getNameCount());
System.out.println("Absolut? : " + relatif.isAbsolute() + " / " + absolut.isAbsolute());
Path gabungan = relatif.getParent().resolve("foto.txt");
Path kusut = Path.of("arsip/./2026/../2026/catatan.txt");
System.out.println("Hasil resolve : " + gabungan);
System.out.println("Sebelum normalize : " + kusut);
System.out.println("Sesudah normalize : " + kusut.normalize());
}
}Path : arsip/2026/catatan.txt
Nama berkas : catatan.txt
Folder induk : arsip/2026
Jumlah elemen nama : 3
Absolut? : false / true
Hasil resolve : arsip/2026/foto.txt
Sebelum normalize : arsip/./2026/../2026/catatan.txt
Sesudah normalize : arsip/2026/catatan.txtgetFileName() mengambil elemen terakhir, getParent() mengambil jalur di depannya, dan getNameCount() menghitung jumlah elemen nama pada jalurnya. Metode resolve() menambahkan nama di ujung jalur, sedangkan normalize() merapikan tanda . dan .. tanpa menyentuh disk. Menjalankan programnya dari terminal cukup dengan satu perintah berikut.
# berada di folder tempat DemoPath.java disimpan
java DemoPath.javaPath : arsip/2026/catatan.txt
Nama berkas : catatan.txt
Folder induk : arsip/2026
Jumlah elemen nama : 3
Absolut? : false / true
Hasil resolve : arsip/2026/foto.txt
Sebelum normalize : arsip/./2026/../2026/catatan.txt
Sesudah normalize : arsip/2026/catatan.txtAnatomi sebuah jalur beserta metode yang paling sering dipakai digambarkan berikut ini.
Utilitas Files untuk operasi nyata#
Semua operasi yang benar-benar menyentuh disk berada di kelas Files sebagai metode static, sehingga kelas ini tidak pernah dibuat sebagai objek dan setiap pemanggilannya diawali nama kelasnya. Files.createDirectories membuat folder beserta seluruh folder induknya tanpa protes bila sudah ada, dan Files.write menyimpan daftar baris ke berkas dalam satu panggilan. Untuk penyalinan dan pemindahan, opsi StandardCopyOption.REPLACE_EXISTING diperlukan bila berkas sasaran boleh ditimpa, sebab tanpa opsi itu kedua operasi melempar FileAlreadyExistsException. Program berikut mempraktikkan siklus lengkapnya, dari membuat hingga menghapus.
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.List;
public class DemoFiles {
public static void main(String[] args) throws IOException {
Path folder = Path.of("arsip");
Path berkas = folder.resolve("catatan.txt");
Files.createDirectories(folder);
Files.write(berkas, List.of("Baris pertama", "Baris kedua"), StandardCharsets.UTF_8);
System.out.println("Ada? : " + Files.exists(berkas));
System.out.println("Ukuran : " + Files.size(berkas) + " byte");
System.out.println("Tipe : berkas " + Files.isRegularFile(berkas)
+ " / folder " + Files.isDirectory(folder));
Path salinan = folder.resolve("catatan-salin.txt");
Files.copy(berkas, salinan, StandardCopyOption.REPLACE_EXISTING);
System.out.println("Salinan ada? " + Files.exists(salinan));
Path pindahan = Path.of("catatan-pindah.txt");
Files.move(salinan, pindahan, StandardCopyOption.REPLACE_EXISTING);
System.out.println("Pindahan ada? " + Files.exists(pindahan) + " (posisi lama: "
+ Files.exists(salinan) + ")");
Files.delete(pindahan);
System.out.println("Setelah dihapus? " + Files.exists(pindahan));
}
}Ada? : true
Ukuran : 26 byte
Tipe : berkas true / folder true
Salinan ada? true
Pindahan ada? true (posisi lama: false)
Setelah dihapus? falseUkuran 26 byte berasal dari 13 karakter baris pertama, 12 karakter baris kedua, ditambah dua pemisah baris. Files.move memindahkan salinan ke luar folder arsip, sehingga pemeriksaan Files.exists(salinan) setelahnya bernilai false. Seluruh operasi di atas melempar IOException, dan deklarasi throws pada main dipakai agar contohnya tetap pendek.
Ada dua metode pembuat folder yang mirip sehingga mudah tertukar. Files.createDirectory menuntut folder induknya sudah ada dan melempar FileAlreadyExistsException bila foldernya sendiri sudah terdaftar, sedangkan Files.createDirectories berlaku seperti mkdir -p pada command line, yaitu membuat seluruh induk yang kurang dan diam saja bila semuanya sudah ada. Untuk penyiapan folder kerja yang bisa dijalankan berulang, versi createDirectories itulah yang aman dipakai.
Menelusuri isi folder#
Files.list mengembalikan Stream<Path> berisi isi satu folder. Urutannya tidak dijamin oleh spesifikasi dan bergantung pada sistem berkas, sehingga contoh mengurutkannya sendiri lewat sorted() sebelum dicetak. Aliran itu membuka penangan berkas di belakang layar, sehingga wajib ditutup, dan try-with-resources mengurus penutupannya. Kata kunci var di sini menyimpulkan tipe Stream<Path> tanpa perlu mengimpor kelasnya.
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
public class DemoDaftarIsi {
public static void main(String[] args) throws IOException {
Path folder = Path.of("log");
Files.createDirectories(folder.resolve("arsip-lama"));
Files.write(folder.resolve("hari-1.txt"),
List.of("Pagi: rapat singkat"), StandardCharsets.UTF_8);
Files.write(folder.resolve("hari-2.txt"),
List.of("Siang: merapikan data"), StandardCharsets.UTF_8);
try (var aliran = Files.list(folder)) {
List<Path> isi = aliran.sorted().toList();
for (Path p : isi) {
String jenis = Files.isDirectory(p) ? "folder" : "berkas";
System.out.println(jenis + ": " + p.getFileName());
}
}
}
}folder: arsip-lama
berkas: hari-1.txt
berkas: hari-2.txtFiles.isDirectory membedakan folder dari berkas biasa, dan hasil pengurutannya berdasarkan nama menjadikan keluaran stabil di mesin mana pun. Untuk folder dengan isi yang sangat banyak, aliran yang diproses seketika seperti ini jauh lebih hemat memori daripada mengumpulkan seluruh jalur terlebih dahulu. Metode saudaranya, Files.walk, menelusuri pohon folder hingga ke subfolder dalamnya, tetapi untuk daftar satu tingkat, Files.list sudah memadai dan hasilnya lebih mudah diurai.
Kesalahan umum#
- Mengira membuat
Pathotomatis membuat berkasnya.Pathhanya teks penunjuk, sedangkan berkas baru tercipta lewatFiles.write,Files.createFile, atauFiles.createDirectories. - Menyalin atau memindah tanpa
StandardCopyOption.REPLACE_EXISTINGke sasaran yang sudah ada. Kedua operasi melemparFileAlreadyExistsExceptionalih-alih menimpa diam-diam. - Memanggil
Files.deletepada folder yang masih berisi. Kegagalannya berupaDirectoryNotEmptyException, sehingga isinya harus dikosongkan lebih dahulu. - Membiarkan hasil
Files.listtanpa penutupan. Penangan folder di belakang aliran itu tetap terbuka, dan pola try-with-resources menutupnya dengan andal.
Ringkasan#
Pathmenunjuk lokasi tanpa menyentuh disk, sedangkan operasi nyata dikerjakan metodestatickelasFiles.Path.ofmembangun jalur lintas sistem operasi, dengan metode sepertigetParent,resolve, dannormalizeyang murni mengolah teks jalur.Filesmenyediakanexists,size,copy,move,delete,write, danreadAllLinesuntuk tugas sehari-hari.Files.listmengembalikanStream<Path>yang urutannya tidak dijamin dan wajib ditutup.
Referensi#
- Path Operations — Oracle — tutorial resmi kelas Path beserta metode-metodenya.
- Files (Java SE 21) — Oracle — dokumentasi utilitas Files untuk seluruh operasi berkas.
- Reading, Writing, and Creating Files — Oracle — tutorial NIO.2 untuk membuat, membuka, membaca, dan menulis berkas.