CodeGym /Java Blog /Acak /File Java, Path
John Squirrels
Level 41
San Francisco

File Java, Path

Dipublikasikan di grup Acak
Hai! Hari ini kita akan berbicara tentang bekerja dengan file dan direktori. Anda sudah tahu cara mengelola konten file: kami telah mendedikasikan banyak pelajaran untuk ini :) Saya rasa Anda akan mudah mengingat beberapa kelas yang digunakan untuk tujuan ini. Dalam pelajaran hari ini, kita akan berbicara secara khusus tentang manajemen file: membuat, mengganti nama, dll. Sebelum Java 7, semua operasi tersebut dilakukan dengan menggunakan kelas File . Anda dapat membacanya di sini . Namun di Java 7, pembuat bahasa memutuskan untuk mengubah cara kami bekerja dengan file dan direktori. Ini terjadi karena kelas File memiliki beberapa kekurangan. Misalnya, ia tidak memiliki metode copy() , yang memungkinkan Anda menyalin file dari satu lokasi ke lokasi lain (kemampuan yang tampaknya penting). Selain itu,Kelas file memiliki beberapa metode yang mengembalikan nilai boolean . Ketika ada kesalahan, metode seperti itu mengembalikan false. Itu tidak mengeluarkan pengecualian, membuatnya sangat sulit untuk mengidentifikasi kesalahan dan mendiagnosis penyebabnya. Di tempat kelas File tunggal , 3 kelas muncul: Paths , Path , dan Files . Tepatnya, Path adalah antarmuka, bukan kelas. Mari kita cari tahu perbedaannya satu sama lain dan mengapa kita membutuhkannya masing-masing. Mari kita mulai dengan yang paling sederhana: Paths .

Jalur

Paths adalah kelas yang sangat sederhana dengan satu metode statis: get() . Itu dibuat semata-mata untuk mendapatkan objek Path dari string atau URI yang diteruskan. Itu tidak memiliki fungsi lain. Berikut adalah contohnya di tempat kerja:

import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {

   public static void main(String[] args) {

       Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
   }
}
Bukan kelas yang paling rumit, bukan? :) Nah, kita juga punya tipe Path ini . Mari kita cari tahu apa itu Path dan mengapa itu dibutuhkan :)

Jalur

Path , pada umumnya, adalah analog yang didesain ulang dari kelas File . Jauh lebih mudah untuk bekerja daripada File . Pertama , banyak metode utilitas (statis) dikeluarkan dan dipindahkan ke kelas Files . Kedua , urutan dikenakan pada nilai kembalian dari metode antarmuka Path . Di kelas File , metode mengembalikan String , atau boolean , atau File . Tidak mudah untuk mengetahuinya. Misalnya, ada metode getParent() yang mengembalikan string yang mewakili jalur induk dari file saat ini. Tapi ada juga ametode getParentFile() , yang mengembalikan hal yang sama tetapi dalam bentuk objek File ! Ini jelas berlebihan. Oleh karena itu, di antarmuka Path , metode getParent() dan metode lain untuk bekerja dengan file cukup mengembalikan objek Path . Tidak ada tumpukan pilihan — semuanya mudah dan sederhana. Apa saja metode berguna yang dimiliki Path ? Berikut beberapa di antaranya dan contoh cara kerjanya:
  • getFileName() : mengembalikan nama file dari jalur;

  • getParent() : mengembalikan direktori "induk" dari jalur saat ini (dengan kata lain, direktori yang terletak tepat di atas pohon direktori);

  • getRoot() : mengembalikan direktori "root", yaitu direktori di bagian atas pohon direktori;

  • startsWith() , endsWith() : periksa apakah jalur dimulai/diakhiri dengan jalur yang diteruskan:

    
    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
           Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
    
           Path fileName = testFilePath.getFileName();
           System.out.println(fileName);
    
           Path parent = testFilePath.getParent();
           System.out.println(parent);
    
           Path root = testFilePath.getRoot();
           System.out.println(root);
    
           boolean endWithTxt = testFilePath.endsWith("Desktop\\testFile.txt");
           System.out.println(endWithTxt);
    
           boolean startsWithLalala = testFilePath.startsWith("lalalala");
           System.out.println(startsWithLalala);
       }
    }
    

    Keluaran konsol:

    
    testFile.txt
    C:\Users\Username\Desktop
    C:\
    true
    false
    

    Perhatikan cara kerja metode endsWith() . Ini memeriksa apakah jalur saat ini berakhir dengan jalur yang dilewati . Khususnya, apakah itu di jalur , bukan di string yang diteruskan .

    Bandingkan hasil dari dua panggilan ini:

    
    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
           Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
    
           System.out.println(testFilePath.endsWith("estFile.txt"));
           System.out.println(testFilePath.endsWith("Desktop\\testFile.txt"));
       }
    }
    

    Keluaran konsol:

    
    false
    true
    

    Metode endWith() harus melewati jalur asli, bukan hanya kumpulan karakter: jika tidak, hasilnya akan selalu salah, bahkan jika jalur saat ini benar-benar diakhiri dengan urutan karakter tersebut (seperti halnya dengan "estFile.txt " pada contoh di atas).

    Selain itu, Path memiliki sekelompok metode yang menyederhanakan bekerja dengan path absolut (penuh) dan relatif .

Mari kita lihat metode ini:
  • boolean isAbsolute() mengembalikan true jika jalur saat ini absolut:

    
    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
           Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
    
           System.out.println(testFilePath.isAbsolute());
       }
    }
    

    Keluaran konsol:

    
    true
    
  • Path normalize() : "menormalkan" jalur saat ini, menghapus elemen yang tidak perlu darinya. Anda mungkin tahu bahwa dalam sistem operasi populer simbol "." (direktori saat ini) dan ".." (direktori induk) sering digunakan untuk menunjuk jalur. Misalnya, " ./Pictures/dog.jpg " berarti direktori saat ini memiliki folder "Pictures", yang kemudian berisi file "dog.jpg".

    Lihat disini. Jika jalan menggunakan "." atau ".." muncul di program Anda, metode normalize() akan menghapusnya dan menghasilkan jalur yang tidak memuatnya:

    
    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
          
           Path path5 = Paths.get("C:\\Users\\Java\\.\\examples");
          
           System.out.println(path5.normalize());
          
           Path path6 = Paths.get("C:\\Users\\Java\\..\\examples");
           System.out.println(path6.normalize());
       }
    }
    

    Keluaran konsol:

    
    C:\Users\Java\examples
    C:\Users\examples
    
  • Path relativize() : menghitung jalur relatif antara jalur saat ini dan jalur yang dilewati.

    Misalnya:

    
    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
           Path testFilePath1 = Paths.get("C:\\Users\\Users\\Users\\Users");
           Path testFilePath2 = Paths.get("C:\\Users\\Users\\Users\\Users\\Username\\Desktop\\testFile.txt");
    
           System.out.println(testFilePath1.relativize(testFilePath2));
       }
    }
    

    Keluaran konsol:

    
    Username\Desktop\testFile.txt
    

Daftar lengkap metode Path cukup panjang. Anda dapat menemukan semuanya dalam dokumentasi Oracle . Sekarang kita akan melanjutkan untuk mempertimbangkan Files .

File

File adalah kelas utilitas yang menyimpan metode statis yang diambil dari kelas File . File sebanding dengan Arrays atau Collections . Perbedaannya adalah ini bekerja dengan file, bukan array atau koleksi :) Ini berfokus pada pengelolaan file dan direktori. Menggunakan metode statis dari kelas Files , kita dapat membuat, menghapus, dan memindahkan file dan direktori. Operasi ini dilakukan menggunakan metode createFile() (untuk direktori, createDirectory() ), move() , dan delete() . Berikut cara menggunakannya:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

public class Main {

   public static void main(String[] args) throws IOException {

       // Create a file
       Path testFile1 = Files.createFile(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt"));
       System.out.println("Was the file created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       // Create a directory
       Path testDirectory = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory"));
       System.out.println("Was the directory created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory")));

       // Move the file from the desktop to the testDirectory directory. When you move a folder, you need to indicate its name in the folder!
       testFile1 = Files.move(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt"), REPLACE_EXISTING);

       System.out.println("Did our file remain on the desktop?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       System.out.println("Has our file been moved to testDirectory?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt")));

       // Delete a file
       Files.delete(testFile1);
       System.out.println("Does the file still exist?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt")));
   }
}
Di sini pertama-tama kita membuat file ( metode Files.createFile() ) di desktop. Kemudian kami membuat folder di lokasi yang sama ( metode Files.createDirectory() ). Setelah itu, kami memindahkan file ( metode Files.move() ) dari desktop ke folder baru ini, dan terakhir kami menghapus file tersebut ( metode Files.delete() ). Keluaran konsol:

Was the file created successfully? 
true 
Was the directory created successfully? 
true
Did our file remain on the desktop? 
false 
Has our file been moved to testDirectory? 
true 
Does the file still exist? 
false
Catatan:seperti metode antarmuka Path, banyak metode kelas FilesmengembalikanPath objek. Sebagian besar metode kelas Filesjuga menggunakan Pathobjek sebagai masukan. Di sini Paths.get()metodenya akan menjadi asisten setia Anda — manfaatkan dengan baik. Apa lagi yang menarik Files? Apa yang benar-benar kurang dari kelas lama Fileadalah sebuah copy()metode! Kami membicarakannya di awal pelajaran ini. Sekarang saatnya untuk bertemu!

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

public class Main {

   public static void main(String[] args) throws IOException {

       // Create a file
       Path testFile1 = Files.createFile(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt"));
       System.out.println("Was the file created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       // Create a directory
       Path testDirectory2 = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2"));
       System.out.println("Was the directory created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2")));

       // Copy the file from the desktop to the testDirectory2 directory.
       testFile1 = Files.copy(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt"), REPLACE_EXISTING);

       System.out.println("Did our file remain on the desktop?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       System.out.println("Was our file copied to testDirectory?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt")));
   }
}
Keluaran konsol:

Was the file created successfully? 
true 
Was the directory created successfully? 
true 
Did our file remain on the desktop? 
true 
Was our file copied to testDirectory? 
true
Sekarang Anda tahu cara menyalin file secara terprogram! :) Tentu saja, Fileskelas memungkinkan Anda tidak hanya mengelola file itu sendiri, tetapi juga bekerja dengan kontennya. Ini memiliki write()metode untuk menulis data ke file, dan ketiga metode untuk membaca data: read(), readAllBytes(), dan readAllLines() Kami akan membahas secara rinci yang terakhir. Kenapa yang itu? Karena memiliki tipe pengembalian yang sangat menarik: List<String>! Artinya, ini mengembalikan daftar semua baris dalam file kepada kita. Tentu saja, ini membuatnya sangat nyaman untuk bekerja dengan konten file, karena seluruh file, baris demi baris, misalnya, dapat ditampilkan di konsol menggunakan loop biasa for:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;

public class Main {

   public static void main(String[] args) throws IOException {

       List<String> lines = Files.readAllLines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"), UTF_8);

       for (String s: lines) {
           System.out.println(s);
       }
   }
}
Keluaran konsol:

I still recall the wondrous moment: 
When you appeared before my sight, 
As though a brief and fleeting omen, 
Pure phantom in enchanting light.
Sangat nyaman! :) Kemampuan ini muncul di Java 7. Stream API muncul di Java 8. Menambahkan beberapa elemen pemrograman fungsional ke Java. Termasuk kemampuan penanganan file yang lebih kaya. Bayangkan kita memiliki tugas berikut: temukan semua baris yang dimulai dengan kata "Sebagai", ubah menjadi HURUF BESAR, dan tampilkan di konsol. Seperti apa solusi menggunakan Fileskelas di Java 7? Sesuatu seperti ini:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;

public class Main {

   public static void main(String[] args) throws IOException {

       List<String> lines = Files.readAllLines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"), UTF_8);

       List<String> result = new ArrayList<>();

       for (String s: lines) {
           if (s.startsWith("As")) {
               String upper = s.toUpperCase();
               result.add(upper);
           }
       }

       for (String s: result) {
           System.out.println(s);
       }
   }
}
Keluaran konsol:

AS THOUGH A BRIEF AND FLEETING OMEN, 
PURE PHANTOM IN ENCHANTING LIGHT.
Misi selesai, tetapi tidakkah Anda berpikir bahwa untuk tugas yang begitu sederhana, kode kita ternyata sedikit... bertele-tele? Menggunakan Stream API Java 8, solusinya terlihat jauh lebih elegan:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {

   public static void main(String[] args) throws IOException {

       Stream<String> stream = Files.lines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"));

       List<String> result  = stream
               .filter(line -> line.startsWith("As"))
               .map(String::toUpperCase)
               .collect(Collectors.toList());
       result.forEach(System.out::println);
   }
}
Kami mencapai hasil yang sama, tetapi dengan kode yang jauh lebih sedikit! Terlebih lagi, tidak ada yang bisa mengatakan bahwa kita telah kehilangan "keterbacaan". Saya pikir Anda dapat dengan mudah mengomentari apa yang dilakukan kode ini, bahkan tanpa terbiasa dengan Stream API. Singkatnya, Stream adalah urutan elemen, di mana Anda dapat melakukan berbagai operasi. Kami mendapatkan objek Stream dari Files.lines()metode, dan kemudian menerapkan 3 fungsi ke dalamnya:
  1. Kami menggunakan filter()metode untuk memilih hanya baris-baris dari file yang dimulai dengan "As".

  2. Kami menelusuri semua baris yang dipilih menggunakan map()metode dan mengonversi masing-masing menjadi UPPERCASE.

  3. Kami menggunakan collect()metode untuk mengumpulkan semua baris yang diterima menjadi file List.

Kami mendapatkan output yang sama:

AS THOUGH A BRIEF AND FLEETING OMEN, 
PURE PHANTOM IN ENCHANTING LIGHT.
Sekarang mari kita kembali ke roti dan mentega kita, yaitu file :) Kemampuan terakhir yang akan kita pertimbangkan hari ini adalah berjalan melalui pohon file . Dalam sistem operasi modern, struktur file paling sering terlihat seperti pohon: ia memiliki akar dan ada cabang, yang dapat memiliki cabang lain, dll. Akar dan cabang adalah direktori. Misalnya, direktori " С:// " mungkin merupakan root. Ini mencakup dua cabang: " C://Downloads " dan " C://Users ". Masing-masing cabang ini memiliki dua cabang: " C://Downloads/Pictures ", " C://Downloads/Video ", " C://Users/JohnSmith ", " C://Users/Pudge2005". Dan cabang-cabang ini pada gilirannya memiliki cabang lain, dll. Dan inilah mengapa kami menyebutnya pohon. Di Linux, strukturnya mirip, tetapi direktori / adalah rootFile, Jalur - 2 . Sekarang bayangkan kita harus mulai dari direktori root , telusuri semua folder dan subfoldernya, dan temukan file yang memiliki konten tertentu. Kami akan mencari file yang berisi baris "Ini adalah file yang kami butuhkan!" Kami akan mengambil folder "testFolder", yang ada di desktop, sebagai direktori root Berikut isinya: File, Jalur - 3Folder level1-a dan level1-b juga berisi folder: File, Jalur - 4File, Jalur - 5Tidak ada folder di "folder level kedua" ini, hanya file individual: File, Jalur - 6File, Jalur - 73 file dengan isi yang kita butuhkan sengaja diberi nama penjelas: FileWeNeed1.txt, FileWeNeed2.txt, FileWeNeed3.txt. Inilah file-file yang perlu kita temukan menggunakan Java. Bagaimana kita melakukan ini? Metode yang sangat ampuh untuk melintasi pohon file membantu kami: Files.walkFileTree (). Inilah yang perlu kita lakukan. Pertama, kita membutuhkan file FileVisitor. FileVisitoradalah antarmuka khusus, di mana metode untuk melintasi pohon file dijelaskan. Secara khusus, di situlah kita akan meletakkan logika untuk membaca konten file dan memeriksa apakah itu berisi teks yang kita butuhkan. Inilah FileVisitorpenampilan kami:

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;

public class MyFileVisitor extends SimpleFileVisitor<Path> {

   @Override
   public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {

       List<String> lines = Files.readAllLines(file);
       for (String s: lines) {
           if (s.contains("This is the file we need")) {
               System.out.println("We found a file we need!");
               System.out.println(file.toAbsolutePath());
               break;
           }
       }

       return FileVisitResult.CONTINUE;
   }
}
Dalam hal ini, kelas kami mewarisi SimpleFileVisitor. Ini adalah kelas yang mengimplementasikan FileVisitor, di mana kita perlu mengganti hanya satu metode: visitFile(). Di sini kami menentukan apa yang perlu dilakukan dengan setiap file di setiap direktori. Jika Anda memerlukan logika yang lebih kompleks untuk melintasi struktur file, Anda harus menulis implementasi Anda sendiri dari FileVisitor. Anda perlu menerapkan 3 metode lagi di kelas itu:
  • preVisitDirectory(): logika untuk mengeksekusi sebelum memasuki folder;

  • visitFileFailed(): logika untuk mengeksekusi jika file tidak dapat dikunjungi (tidak ada akses, atau karena alasan lain);

  • postVisitDirectory(): logika untuk mengeksekusi setelah memasuki folder.

Kami tidak memerlukan logika seperti itu dieksekusi, jadi kami baik-baik saja dengan SimpleFileVisitor. Logika di dalam visitFile()metode ini cukup sederhana: baca semua baris dalam file, periksa apakah berisi konten yang kita butuhkan, dan jika demikian, cetak jalur absolut di konsol. Satu-satunya baris yang mungkin membuat Anda kesulitan adalah yang ini:

return FileVisitResult.CONTINUE;
Sebenarnya, ini sangat sederhana. Di sini kami hanya menjelaskan apa yang harus dilakukan program setelah file dikunjungi dan semua operasi yang diperlukan telah dilakukan. Dalam kasus kami, kami ingin melanjutkan melintasi pohon, jadi kami memilih opsi CONTINUE. Namun, alternatifnya, kita mungkin memiliki tujuan yang berbeda: alih-alih menemukan semua file yang berisi "Ini adalah file yang kita butuhkan", temukan hanya satu file tersebut . Setelah itu, program harus dihentikan. Dalam hal ini, kode kita akan terlihat persis sama, tetapi alih-alih rusak akan ada:

return FileVisitResult.TERMINATE;
Baiklah, mari jalankan kode kita dan lihat apakah berhasil.

import java.io.IOException;
import java.nio.file.*;

public class Main {

   public static void main(String[] args) throws IOException {

       Files.walkFileTree(Paths.get("C:\\Users\\Username\\Desktop\\testFolder"), new MyFileVisitor());
   }
}
Keluaran konsol:

We found a file we need! 
C:\Users\Username\Desktop\testFolder\FileWeNeed1.txt 
We found a file we need! 
C:\Users\Username\Desktop\testFolder\level1-a\level2-a-a\FileWeNeed2.txt 
We found a file we need! 
C:\Users\Username\Desktop\testFolder\level1-b\level2-b-b\FileWeNeed3.txt
Bagus sekali! Itu berhasil! :) Anda juga dapat menerima tantangan kecil ini: ganti SimpleFileVisitordengan yang biasa FileVisitor, ganti semua 4 metode, dan buat tujuan Anda sendiri untuk program tersebut. Misalnya, Anda dapat menulis program yang mencatat semua tindakannya: tampilkan nama file atau folder sebelum atau setelah memasukkannya. Itu saja untuk saat ini. Sampai berjumpa lagi! :)
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION