Pengantar API File Java NIO2

1. Ikhtisar

Pada artikel ini, kita akan fokus pada I / O API baru di Platform Java - NIO2 - untuk melakukan manipulasi file dasar .

File API di NIO2 merupakan salah satu area fungsional utama baru dari Platform Java yang dikirimkan dengan Java 7, khususnya subset dari API sistem file baru bersama API Path.

2. Penyiapan

Menyiapkan proyek Anda untuk menggunakan API File hanyalah masalah membuat impor ini:

import java.nio.file.*;

Karena contoh kode dalam artikel ini mungkin akan berjalan di lingkungan yang berbeda, mari kita lihat direktori home pengguna, yang akan berlaku di semua sistem operasi:

private static String HOME = System.getProperty("user.home");

Kelas Files adalah salah satu titik masuk utama dari paket java.nio.file . Kelas ini menawarkan sekumpulan API yang kaya untuk membaca, menulis, dan memanipulasi file dan direktori. Metode kelas File bekerja pada contoh objek Path .

3. Memeriksa File atau Direktori

Kita dapat memiliki contoh Path yang merepresentasikan file atau direktori pada sistem file. Apakah file atau direktori yang dituju ada atau tidak, dapat diakses atau tidak, dapat dikonfirmasi dengan operasi file.

Demi kesederhanaan, setiap kali kami menggunakan istilah file , kami akan merujuk ke file dan direktori kecuali dinyatakan lain secara eksplisit.

Untuk memeriksa apakah sebuah file ada, kami menggunakan API yang ada :

@Test public void givenExistentPath_whenConfirmsFileExists_thenCorrect() { Path p = Paths.get(HOME); assertTrue(Files.exists(p)); }

Untuk memeriksa bahwa file tidak ada, kami menggunakan API notExists :

@Test public void givenNonexistentPath_whenConfirmsFileNotExists_thenCorrect() { Path p = Paths.get(HOME + "/inexistent_file.txt"); assertTrue(Files.notExists(p)); }

Kami juga dapat memeriksa apakah suatu file adalah file biasa seperti myfile.txt atau hanya sebuah direktori, kami menggunakan API isRegularFile :

@Test public void givenDirPath_whenConfirmsNotRegularFile_thenCorrect() { Path p = Paths.get(HOME); assertFalse(Files.isRegularFile(p)); }

Ada juga metode statis untuk memeriksa izin file. Untuk memeriksa apakah suatu file dapat dibaca, kami menggunakan API isReadable :

@Test public void givenExistentDirPath_whenConfirmsReadable_thenCorrect() { Path p = Paths.get(HOME); assertTrue(Files.isReadable(p)); }

Untuk memeriksa apakah itu dapat ditulis, kami menggunakan API isWritable :

@Test public void givenExistentDirPath_whenConfirmsWritable_thenCorrect() { Path p = Paths.get(HOME); assertTrue(Files.isWritable(p)); }

Demikian pula, untuk memeriksa apakah itu dapat dieksekusi:

@Test public void givenExistentDirPath_whenConfirmsExecutable_thenCorrect() { Path p = Paths.get(HOME); assertTrue(Files.isExecutable(p)); }

Saat kami memiliki dua jalur, kami dapat memeriksa apakah keduanya mengarah ke file yang sama di sistem file yang mendasarinya:

@Test public void givenSameFilePaths_whenConfirmsIsSame_thenCorrect() { Path p1 = Paths.get(HOME); Path p2 = Paths.get(HOME); assertTrue(Files.isSameFile(p1, p2)); }

4. Membuat File

API sistem file menyediakan operasi baris tunggal untuk membuat file. Untuk membuat file biasa, kami menggunakan createFile API dan meneruskan ke objek Path yang mewakili file yang ingin kami buat.

Semua elemen nama di jalur harus ada, selain dari nama file, jika tidak, kita akan mendapatkan IOException:

@Test public void givenFilePath_whenCreatesNewFile_thenCorrect() { String fileName = "myfile_" + UUID.randomUUID().toString() + ".txt"; Path p = Paths.get(HOME + "/" + fileName); assertFalse(Files.exists(p)); Files.createFile(p); assertTrue(Files.exists(p)); }

Dalam pengujian di atas, saat kami pertama kali memeriksa jalurnya, itu tidak ada, kemudian setelah operasi createFile , ditemukan ada.

Untuk membuat direktori, kami menggunakan API createDirectory :

@Test public void givenDirPath_whenCreatesNewDir_thenCorrect() { String dirName = "myDir_" + UUID.randomUUID().toString(); Path p = Paths.get(HOME + "/" + dirName); assertFalse(Files.exists(p)); Files.createDirectory(p); assertTrue(Files.exists(p)); assertFalse(Files.isRegularFile(p)); assertTrue(Files.isDirectory(p)); }

Operasi ini mengharuskan semua elemen nama di jalur ada, jika tidak, kita juga mendapatkan IOException :

@Test(expected = NoSuchFileException.class) public void givenDirPath_whenFailsToCreateRecursively_thenCorrect() { String dirName = "myDir_" + UUID.randomUUID().toString() + "/subdir"; Path p = Paths.get(HOME + "/" + dirName); assertFalse(Files.exists(p)); Files.createDirectory(p); }

Namun, jika kami ingin membuat hierarki direktori dengan satu panggilan, kami menggunakan metode createDirectories . Tidak seperti operasi sebelumnya, ketika menemukan elemen nama yang hilang di jalur, itu tidak melempar IOException , itu membuatnya secara rekursif mengarah ke elemen terakhir:

@Test public void givenDirPath_whenCreatesRecursively_thenCorrect() { Path dir = Paths.get( HOME + "/myDir_" + UUID.randomUUID().toString()); Path subdir = dir.resolve("subdir"); assertFalse(Files.exists(dir)); assertFalse(Files.exists(subdir)); Files.createDirectories(subdir); assertTrue(Files.exists(dir)); assertTrue(Files.exists(subdir)); }

5. Membuat File Sementara

Banyak aplikasi membuat jejak file sementara dalam sistem file saat dijalankan. Akibatnya, sebagian besar sistem file memiliki direktori khusus untuk menyimpan file sementara yang dibuat oleh aplikasi semacam itu.

API sistem file baru menyediakan operasi khusus untuk tujuan ini. The createTempFile API melakukan operasi ini. Dibutuhkan objek jalur, awalan file, dan akhiran file:

@Test public void givenFilePath_whenCreatesTempFile_thenCorrect() { String prefix = "log_"; String suffix = ".txt"; Path p = Paths.get(HOME + "/"); Files.createTempFile(p, prefix, suffix); assertTrue(Files.exists(p)); }

Parameter ini cukup untuk persyaratan yang membutuhkan operasi ini. Namun, jika Anda perlu menentukan atribut file tertentu, ada parameter argumen variabel keempat.

Tes di atas membuat file sementara di direktori HOME , mendahului dan menambahkan string awalan dan sufiks yang disediakan masing-masing. Kami akan berakhir dengan nama file seperti log_8821081429012075286.txt . String numerik panjang dihasilkan oleh sistem.

Namun, jika kami tidak memberikan prefiks dan sufiks, maka nama file hanya akan menyertakan string numerik panjang dan ekstensi .tmp default :

@Test public void givenPath_whenCreatesTempFileWithDefaults_thenCorrect() { Path p = Paths.get(HOME + "/"); Files.createTempFile(p, null, null); assertTrue(Files.exists(p)); }

Operasi di atas membuat file dengan nama seperti 8600179353689423985.tmp .

Terakhir, jika kami tidak memberikan jalur, awalan, atau akhiran, maka operasi akan menggunakan default di seluruh bagian. Lokasi default dari file yang dibuat adalah sistem file yang menyediakan direktori file sementara:

@Test public void givenNoFilePath_whenCreatesTempFileInTempDir_thenCorrect() { Path p = Files.createTempFile(null, null); assertTrue(Files.exists(p)); }

Di windows, ini akan default ke sesuatu seperti C: \ Users \ user \ AppData \ Local \ Temp \ 6100927974988978748.tmp .

Semua operasi di atas dapat disesuaikan untuk membuat direktori daripada file biasa dengan menggunakan createTempDirectory daripada createTempFile .

6. Menghapus File

Untuk menghapus file, kami menggunakan API delete . Untuk tujuan kejelasan, pengujian berikut terlebih dahulu memastikan bahwa file tersebut belum ada, kemudian membuatnya dan mengonfirmasi bahwa sekarang ada dan akhirnya menghapusnya dan mengonfirmasi bahwa file tersebut sudah tidak ada lagi:

@Test public void givenPath_whenDeletes_thenCorrect() { Path p = Paths.get(HOME + "/fileToDelete.txt"); assertFalse(Files.exists(p)); Files.createFile(p); assertTrue(Files.exists(p)); Files.delete(p); assertFalse(Files.exists(p)); }

Namun, jika file tidak ada di sistem file, operasi penghapusan akan gagal dengan IOException :

@Test(expected = NoSuchFileException.class) public void givenInexistentFile_whenDeleteFails_thenCorrect() { Path p = Paths.get(HOME + "/inexistentFile.txt"); assertFalse(Files.exists(p)); Files.delete(p); }

Kami dapat menghindari skenario ini dengan menggunakan deleteIfExists yang gagal diam-diam jika file tidak ada. Ini penting ketika beberapa utas melakukan operasi ini dan kami tidak menginginkan pesan kegagalan hanya karena utas melakukan operasi lebih awal dari utas saat ini yang gagal:

@Test public void givenInexistentFile_whenDeleteIfExistsWorks_thenCorrect() { Path p = Paths.get(HOME + "/inexistentFile.txt"); assertFalse(Files.exists(p)); Files.deleteIfExists(p); }

Ketika berhadapan dengan direktori dan bukan file biasa, kita harus ingat bahwa operasi delete tidak bekerja secara rekursif secara default. Jadi, jika direktori tidak kosong, itu akan gagal dengan IOException :

@Test(expected = DirectoryNotEmptyException.class) public void givenPath_whenFailsToDeleteNonEmptyDir_thenCorrect() { Path dir = Paths.get( HOME + "/emptyDir" + UUID.randomUUID().toString()); Files.createDirectory(dir); assertTrue(Files.exists(dir)); Path file = dir.resolve("file.txt"); Files.createFile(file); Files.delete(dir); assertTrue(Files.exists(dir)); }

7. Menyalin File

Anda dapat menyalin file atau direktori dengan menggunakan copy API:

@Test public void givenFilePath_whenCopiesToNewLocation_thenCorrect() { Path dir1 = Paths.get( HOME + "/firstdir_" + UUID.randomUUID().toString()); Path dir2 = Paths.get( HOME + "/otherdir_" + UUID.randomUUID().toString()); Files.createDirectory(dir1); Files.createDirectory(dir2); Path file1 = dir1.resolve("filetocopy.txt"); Path file2 = dir2.resolve("filetocopy.txt"); Files.createFile(file1); assertTrue(Files.exists(file1)); assertFalse(Files.exists(file2)); Files.copy(file1, file2); assertTrue(Files.exists(file2)); }

The copy fails if the target file exists unless the REPLACE_EXISTING option is specified:

@Test(expected = FileAlreadyExistsException.class) public void givenPath_whenCopyFailsDueToExistingFile_thenCorrect() { Path dir1 = Paths.get( HOME + "/firstdir_" + UUID.randomUUID().toString()); Path dir2 = Paths.get( HOME + "/otherdir_" + UUID.randomUUID().toString()); Files.createDirectory(dir1); Files.createDirectory(dir2); Path file1 = dir1.resolve("filetocopy.txt"); Path file2 = dir2.resolve("filetocopy.txt"); Files.createFile(file1); Files.createFile(file2); assertTrue(Files.exists(file1)); assertTrue(Files.exists(file2)); Files.copy(file1, file2); Files.copy(file1, file2, StandardCopyOption.REPLACE_EXISTING); }

However, when copying directories, the contents are not copied recursively. This means that if /baeldung contains /articles.db and /authors.db files, copying /baeldung to a new location will create an empty directory.

8. Moving Files

You can move a file or directory by using the move API. It is in most ways similar to the copy operation. If the copy operation is analogous to a copy and paste operation in GUI based systems, then move is analogous to a cut and paste operation:

@Test public void givenFilePath_whenMovesToNewLocation_thenCorrect() { Path dir1 = Paths.get( HOME + "/firstdir_" + UUID.randomUUID().toString()); Path dir2 = Paths.get( HOME + "/otherdir_" + UUID.randomUUID().toString()); Files.createDirectory(dir1); Files.createDirectory(dir2); Path file1 = dir1.resolve("filetocopy.txt"); Path file2 = dir2.resolve("filetocopy.txt"); Files.createFile(file1); assertTrue(Files.exists(file1)); assertFalse(Files.exists(file2)); Files.move(file1, file2); assertTrue(Files.exists(file2)); assertFalse(Files.exists(file1)); }

The Langkah operasi gagal jika file target ada kecuali REPLACE_EXISTING opsi ditentukan seperti yang kami lakukan dengan copy operasi:

@Test(expected = FileAlreadyExistsException.class) public void givenFilePath_whenMoveFailsDueToExistingFile_thenCorrect() { Path dir1 = Paths.get( HOME + "/firstdir_" + UUID.randomUUID().toString()); Path dir2 = Paths.get( HOME + "/otherdir_" + UUID.randomUUID().toString()); Files.createDirectory(dir1); Files.createDirectory(dir2); Path file1 = dir1.resolve("filetocopy.txt"); Path file2 = dir2.resolve("filetocopy.txt"); Files.createFile(file1); Files.createFile(file2); assertTrue(Files.exists(file1)); assertTrue(Files.exists(file2)); Files.move(file1, file2); Files.move(file1, file2, StandardCopyOption.REPLACE_EXISTING); assertTrue(Files.exists(file2)); assertFalse(Files.exists(file1)); }

9. Kesimpulan

Di artikel ini, kami mempelajari tentang API file di API sistem file baru (NIO2) yang dikirimkan sebagai bagian dari Java 7 dan melihat sebagian besar operasi file penting beraksi.

Contoh kode yang digunakan dalam artikel ini dapat ditemukan di proyek Github artikel.