Pengenalan API Java NIO2 File

1. Gambaran keseluruhan

Dalam artikel ini, kita akan fokus pada API I / O baru di Platform Java - NIO2 - untuk melakukan manipulasi fail asas .

File API di NIO2 merupakan salah satu bidang fungsional baru dari Platform Java yang dikirimkan dengan Java 7, khususnya subset API sistem fail baru di samping Path API.

2. Persediaan

Menyiapkan projek anda untuk menggunakan API Fail hanya dengan membuat import ini:

import java.nio.file.*;

Oleh kerana sampel kod dalam artikel ini mungkin akan berjalan di persekitaran yang berbeza, mari kita menangani direktori utama pengguna, yang akan berlaku di semua sistem operasi:

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

The Files kelas adalah salah satu daripada pintu masuk utama yang java.nio.file pakej. Kelas ini menawarkan banyak API untuk membaca, menulis, dan memanipulasi fail dan direktori. The Files kaedah kelas bekerja pada contoh Path objek.

3. Memeriksa Fail atau Direktori

Kita dapat memiliki contoh Path yang mewakili file atau direktori pada sistem file. Sama ada fail atau direktori yang dituju ada atau tidak, dapat diakses atau tidak dapat disahkan oleh operasi fail.

Demi kesederhanaan, setiap kali kita menggunakan istilah file , kita akan merujuk kepada kedua-dua fail dan direktori kecuali dinyatakan sebaliknya.

Untuk memeriksa apakah ada fail, kami menggunakan API yang ada :

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

Untuk memastikan fail tidak ada, kami menggunakan notExists API:

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

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

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

Terdapat juga kaedah statik untuk memeriksa kebenaran fail. Untuk memeriksa sama ada fail dapat dibaca, kami menggunakan isReadable API:

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

Untuk memeriksa sama ada ia boleh ditulis, kami menggunakan isWritable API:

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

Begitu juga, untuk memeriksa sama ada ia boleh dilaksanakan:

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

Apabila kita mempunyai dua jalur, kita dapat memeriksa apakah keduanya menunjuk ke fail yang sama pada sistem fail yang mendasari:

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

4. Membuat Fail

API sistem fail menyediakan operasi satu baris untuk membuat fail. Untuk membuat fail biasa, kami menggunakan createFile API dan meneruskannya objek Path yang mewakili fail yang ingin kami buat.

Semua elemen nama dalam laluan mesti ada, selain dari nama fail, jika tidak, kami akan mendapat 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 ujian di atas, ketika kita pertama kali memeriksa jalan itu, ia tidak ada, kemudian setelah operasi createFile , didapati 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 memerlukan semua elemen nama di jalan ada, jika tidak, kita juga mendapat 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); }

Walau bagaimanapun, jika kita ingin membuat hierarki direktori dengan satu panggilan, kita menggunakan kaedah createDirectories . Tidak seperti operasi sebelumnya, ketika menghadapi unsur nama yang hilang di jalan, ia tidak membuang IOException , ia menjadikannya berulang kali 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 Fail Sementara

Banyak aplikasi membuat jejak fail sementara dalam sistem fail semasa dijalankan. Akibatnya, kebanyakan sistem fail memiliki direktori khusus untuk menyimpan fail sementara yang dihasilkan oleh aplikasi tersebut.

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

@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 mencukupi untuk keperluan yang memerlukan operasi ini. Namun, jika anda perlu menentukan atribut khusus fail, ada parameter argumen pemboleh ubah keempat.

Ujian di atas membuat fail sementara di direktori HOME , pra-menunggu dan menambahkan rentetan awalan dan akhiran yang disediakan. Kami akan berakhir dengan nama fail seperti log_8821081429012075286.txt . Rentetan berangka panjang dihasilkan oleh sistem.

Namun, jika kami tidak memberikan awalan dan akhiran, maka nama fail hanya akan menyertakan rentetan angka panjang dan sambungan .tmp lalai :

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

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

Akhirnya, jika kita tidak memberikan jalan, awalan atau akhiran, operasi akan menggunakan lalai sepanjang masa. Lokasi lalai dari fail yang dibuat adalah sistem fail yang disediakan sebagai direktori fail sementara:

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

Pada tetingkap, ini akan ditetapkan seperti C: \ Users \ user \ AppData \ Local \ Temp \ 6100927974988978748.tmp .

Semua operasi di atas dapat disesuaikan untuk membuat direktori dan bukannya fail biasa dengan menggunakan createTempDirectory dan bukannya createTempFile .

6. Memadam Fail

Untuk menghapus fail, kami menggunakan API hapus . Untuk tujuan kejelasan, ujian berikut terlebih dahulu memastikan bahawa fail itu belum ada, kemudian membuatnya dan mengesahkan bahawa sekarang ada dan akhirnya menghapusnya dan mengesahkan bahawa fail itu tidak lagi wujud:

@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 fail tidak ada dalam sistem fail, operasi hapus 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); }

Kita boleh mengelakkan senario ini dengan menggunakan deleteIfExists yang gagal secara senyap sekiranya fail tidak wujud. Ini penting ketika banyak utas melakukan operasi ini dan kami tidak mahu mesej kegagalan hanya kerana utas melakukan operasi lebih awal daripada utas semasa yang gagal:

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

Semasa berurusan dengan direktori dan bukan fail biasa, kita harus ingat bahawa operasi hapus tidak berfungsi secara berulang secara lalai. Oleh itu, jika direktori tidak kosong, ia 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 Fail

Anda boleh menyalin fail atau direktori dengan menggunakan API salin :

@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)); }

Salinan gagal jika fail sasaran ada kecuali pilihan REPLACE_EXISTING ditentukan:

@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); }

Walau bagaimanapun, semasa menyalin direktori, kandungannya tidak disalin secara berulang. Ini bermaksud jika / baeldung mengandungi /articles.db dan /authors.db file, menyalin / baeldung ke lokasi baru akan membuat direktori kosong.

8. Memindahkan Fail

Anda dapat memindahkan fail atau direktori dengan menggunakan API pindah . Ini dalam banyak cara serupa dengan operasi salin . Sekiranya operasi salin serupa dengan operasi salin dan tampal dalam sistem berasaskan GUI, maka pindah adalah serupa dengan operasi pemotongan dan tampal :

@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 fail sasaran wujud melainkan jika REPLACE_EXISTING pilihan ditentukan seperti yang kita lakukan dengan salinan 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. Kesimpulannya

Dalam artikel ini, kami mengetahui tentang API file dalam API sistem fail baru (NIO2) yang dikirimkan sebagai bagian dari Java 7 dan melihat sebagian besar operasi fail penting dalam tindakan.

Contoh kod yang digunakan dalam artikel ini boleh didapati di projek Github artikel.