CodeGym/Blog Java/rawak/Fail Java, Laluan
John Squirrels
Tahap
San Francisco

Fail Java, Laluan

Diterbitkan dalam kumpulan
Hai! Hari ini kita akan bercakap tentang bekerja dengan fail dan direktori. Anda sudah tahu cara mengurus kandungan fail: kami telah mendedikasikan banyak pelajaran untuk perkara ini :) Saya rasa anda mudah mengingati beberapa kelas yang digunakan untuk tujuan ini. Dalam pelajaran hari ini, kita akan bercakap secara khusus tentang pengurusan fail: mencipta, menamakan semula, dll. Sebelum Java 7, semua operasi sedemikian dilakukan menggunakan kelas Fail . Anda boleh membaca mengenainya di sini . Tetapi dalam Java 7, pencipta bahasa memutuskan untuk menukar cara kami bekerja dengan fail dan direktori. Ini berlaku kerana kelas Fail mempunyai beberapa kelemahan. Sebagai contoh, ia tidak mempunyai kaedah copy() , yang membolehkan anda menyalin fail dari satu lokasi ke lokasi lain (keupayaan yang kelihatan penting). Selain itu,Kelas fail mempunyai beberapa kaedah yang mengembalikan nilai boolean . Apabila terdapat ralat, kaedah sedemikian mengembalikan palsu. Ia tidak membuang pengecualian, menjadikannya sangat sukar untuk mengenal pasti ralat dan mendiagnosis puncanya. Di tempat kelas Fail tunggal , 3 kelas muncul: Paths , Path , dan Files . Nah, lebih tepatnya, Path ialah antara muka, bukan kelas. Mari kita fikirkan bagaimana mereka berbeza antara satu sama lain dan mengapa kita memerlukan setiap daripada mereka. Mari kita mulakan dengan yang paling mudah: Paths .

Laluan

Paths ialah kelas yang sangat mudah dengan satu kaedah statik: get() . Ia dicipta semata-mata untuk mendapatkan objek Path daripada rentetan atau URI yang diluluskan. Ia tidak mempunyai fungsi lain. Berikut ialah contoh 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 kompleks, bukan? :) Nah, kami juga mempunyai jenis Laluan ini . Mari kita ketahui apa itu Path dan mengapa ia diperlukan :)

Laluan

Path , pada umumnya, ialah analog yang direka bentuk semula bagi kelas Fail . Ia lebih mudah untuk digunakan daripada File . Pertama , banyak kaedah utiliti (statik) telah dikeluarkan dan dipindahkan ke kelas Fail . Kedua , perintah telah dikenakan ke atas nilai pulangan kaedah antara muka Laluan . Dalam kelas Fail , kaedah mengembalikan sama ada String , atau boolean , atau File . Ia tidak mudah untuk memikirkannya. Sebagai contoh, terdapat kaedah getParent() yang mengembalikan rentetan yang mewakili laluan induk fail semasa. Tetapi terdapat juga akaedah getParentFile() , yang mengembalikan perkara yang sama tetapi dalam bentuk objek Fail ! Ini jelas berlebihan. Oleh itu, dalam antara muka Path , kaedah getParent() dan kaedah lain untuk bekerja dengan fail hanya mengembalikan objek Path . Tiada timbunan pilihan — semuanya mudah dan ringkas. Apakah beberapa kaedah berguna yang ada pada Path ? Berikut ialah beberapa daripada mereka dan contoh cara mereka berfungsi:
  • getFileName() : mengembalikan nama fail daripada laluan;

  • getParent() : mengembalikan direktori "ibu bapa" laluan semasa (dengan kata lain, direktori yang terletak betul-betul di atas dalam pepohon direktori);

  • getRoot() : mengembalikan direktori "root", iaitu direktori di bahagian atas pokok direktori;

  • startsWith() , endsWith() : semak sama ada laluan bermula/berakhir dengan laluan yang diluluskan:

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

    Output konsol:

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

    Beri perhatian kepada cara kaedah endsWith() berfungsi. Ia menyemak sama ada laluan semasa berakhir dengan laluan yang diluluskan . Khususnya, sama ada ia berada dalam laluan , bukan dalam rentetan yang diluluskan .

    Bandingkan keputusan kedua-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"));
       }
    }

    Output konsol:

    false
    true

    Kaedah endsWith() mesti lulus laluan tulen, bukan hanya satu set aksara: jika tidak, hasilnya akan sentiasa palsu, walaupun laluan semasa benar-benar berakhir dengan jujukan aksara itu (seperti yang berlaku dengan "estFile.txt "dalam contoh di atas).

    Selain itu, Path mempunyai sekumpulan kaedah yang memudahkan kerja dengan laluan mutlak (penuh) dan relatif .

Mari lihat kaedah ini:
  • boolean isAbsolute() mengembalikan benar jika laluan semasa adalah mutlak:

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

    Output konsol:

    true
  • Path normalize() : "menormalkan" laluan semasa, mengalih keluar elemen yang tidak perlu daripadanya. Anda mungkin tahu bahawa dalam sistem pengendalian popular simbol "." (direktori semasa) dan ".." (direktori induk) sering digunakan untuk menetapkan laluan. Contohnya, " ./Pictures/dog.jpg " bermaksud direktori semasa mempunyai folder "Pictures", yang seterusnya mengandungi fail "dog.jpg".

    Tengok sini. Jika laluan menggunakan "." atau ".." muncul dalam program anda, kaedah normalize() akan mengalih keluarnya dan menghasilkan laluan yang tidak mengandunginya:

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

    Output konsol:

    C:\Users\Java\examples
    C:\Users\examples
  • Path relativize() : mengira laluan relatif antara laluan semasa dan laluan yang dilalui.

    Sebagai contoh:

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

    Output konsol:

    Username\Desktop\testFile.txt

Senarai lengkap kaedah Path agak panjang. Anda boleh menemui kesemuanya dalam dokumentasi Oracle . Sekarang kita akan meneruskan untuk mempertimbangkan Files .

Fail

Fail ialah kelas utiliti yang memegang kaedah statik yang diambil daripada kelas Fail . Fail adalah setanding dengan Tatasusunan atau Koleksi . Perbezaannya ialah ia berfungsi dengan fail, bukan tatasusunan atau koleksi :) Ia memberi tumpuan kepada mengurus fail dan direktori. Menggunakan kaedah statik kelas Fail , kami boleh mencipta, memadam dan memindahkan fail dan direktori. Operasi ini dilakukan menggunakankaedah createFile() (untuk direktori, createDirectory() ), move() dan delete() . Begini 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 kita mula-mula mencipta fail ( kaedah Files.createFile() pada desktop. Kemudian kami mencipta folder di lokasi yang sama ( kaedah Files.createDirectory() ). Selepas itu, kami mengalihkan fail ( kaedah Files.move() dari desktop ke folder baharu ini, dan akhirnya kami memadamkan fail ( kaedah Files.delete() ). Output 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 kaedah antara Pathmuka, banyak kaedah kelas FilesmengembalikanPath objek. Kebanyakan kaedah kelas Filesjuga mengambil Pathobjek sebagai input. Di sini kaedah itu Paths.get()akan menjadi pembantu setia anda — gunakannya dengan sebaiknya. Apa lagi yang menarik Files? FileApa yang sebenarnya kekurangan kelas lama ialah copy()kaedah! Kami bercakap mengenainya pada permulaan pelajaran ini. Kini tiba masanya untuk bertemu dengannya!
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")));
   }
}
Output 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 fail secara pemrograman! :) Sudah tentu, Fileskelas itu membolehkan anda bukan sahaja mengurus fail itu sendiri, tetapi juga berfungsi dengan kandungannya. Ia mempunyai write()kaedah untuk menulis data ke fail, dan kesemua 3 kaedah untuk membaca data: read(), readAllBytes(), dan readAllLines() Kami akan membincangkan secara terperinci tentang yang terakhir. Kenapa yang itu? Kerana ia mempunyai jenis pulangan yang sangat menarik: List<String>! Iaitu, ia mengembalikan kita senarai semua baris dalam fail. Sudah tentu, ini menjadikannya sangat mudah untuk bekerja dengan kandungan fail, kerana keseluruhan fail, baris demi baris, boleh, sebagai contoh, dipaparkan pada konsol menggunakan gelung 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);
       }
   }
}
Output 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 mudah! :) Keupayaan ini muncul dalam Java 7. Stream API muncul dalam Java 8. Ia menambahkan beberapa elemen pengaturcaraan berfungsi pada Java. Termasuk keupayaan pengendalian fail yang lebih kaya. Bayangkan kita mempunyai tugas berikut: cari semua baris yang bermula dengan perkataan "As", tukarkannya kepada HURUF BESAR, dan paparkannya pada konsol. Apakah rupa penyelesaian menggunakan Fileskelas dalam 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);
       }
   }
}
Output konsol:
AS THOUGH A BRIEF AND FLEETING OMEN,
PURE PHANTOM IN ENCHANTING LIGHT.
Misi tercapai, tetapi tidakkah anda berfikir bahawa untuk tugas yang begitu mudah, kod kami ternyata sedikit... verbose? Menggunakan API Stream Java 8, penyelesaiannya kelihatan 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 lebih sedikit kod! Apatah lagi, tiada siapa yang boleh mengatakan bahawa kita telah kehilangan "kebolehbacaan". Saya rasa anda boleh mengulas dengan mudah tentang perkara yang dilakukan oleh kod ini, walaupun tanpa mengetahui API Strim. Ringkasnya, Strim ialah jujukan elemen, di mana anda boleh melakukan pelbagai operasi. Kami mendapat objek Stream daripada Files.lines()kaedah, dan kemudian menggunakan 3 fungsi padanya:
  1. Kami menggunakan filter()kaedah untuk memilih hanya baris tersebut daripada fail yang bermula dengan "As".

  2. Kami berjalan melalui semua baris yang dipilih menggunakan map()kaedah dan menukar setiap baris kepada HURUF BESAR.

  3. Kami menggunakan collect()kaedah untuk mengumpulkan semua baris yang diterima ke dalam List.

Kami mendapat output yang sama:
AS THOUGH A BRIEF AND FLEETING OMEN,
PURE PHANTOM IN ENCHANTING LIGHT.
Sekarang mari kita kembali kepada roti dan mentega kita, iaitu fail :) Keupayaan terakhir yang akan kita pertimbangkan hari ini ialah berjalan melalui pokok fail . Dalam sistem pengendalian moden, struktur fail paling kerap kelihatan seperti pokok: ia mempunyai akar dan terdapat cawangan, yang boleh mempunyai cawangan lain, dll. Akar dan cawangan adalah direktori. Sebagai contoh, direktori " С:// " mungkin akarnya. Ia termasuk dua cawangan: " C://Downloads " dan " C://Users ". Setiap cawangan ini mempunyai dua cawangan: " C://Downloads/Pictures ", " C://Downloads/Video ", " C://Users/JohnSmith ", " C://Users/Pudge2005". Dan cawangan ini pula mempunyai cawangan lain, dsb. dan inilah sebabnya kami memanggilnya pokok. Di Linux, strukturnya serupa, tetapi direktori / adalah akarnya. Sekarang bayangkanFail, Laluan - 2 bahawa kita perlu bermula pada direktori akar , berjalan melalui semua folder dan subfoldernya, dan cari fail yang mempunyai beberapa kandungan tertentu. Kami akan mencari fail yang mengandungi baris "Ini adalah fail yang kami perlukan!" Kami akan mengambil folder "testFolder", yang dihidupkan. desktop, sebagai direktori akar. Berikut ialah kandungannya: Fail, Laluan - 3Folder level1-a dan level1-b juga mengandungi folder: Fail, Laluan - 4Fail, Laluan - 5Tiada folder dalam "folder peringkat kedua" ini, hanya fail individu: Fail, Laluan - 6Fail, Laluan - 73 fail dengan kandungan yang kami perlukan sengaja diberi nama penjelasan: FileWeNeed1.txt, FileWeNeed2.txt, FileWeNeed3.txt. Ini adalah tepat fail yang perlu kami cari menggunakan Java. Bagaimana kita melakukan ini? Kaedah yang sangat berkuasa untuk melintasi pokok fail membantu kami: Files.walkFileTree (). Inilah yang perlu kita lakukan. Pertama, kita memerlukan FileVisitor. FileVisitorialah antara muka khas, di mana kaedah untuk melintasi pokok fail diterangkan. Khususnya, di situlah kita akan meletakkan logik untuk membaca kandungan fail dan menyemak sama ada ia mengandungi teks yang kita perlukan. Inilah FileVisitorrupa 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 kes ini, kelas kami mewarisi SimpleFileVisitor. Ini ialah kelas yang melaksanakan FileVisitor, di mana kita perlu mengatasi hanya satu kaedah: visitFile(). Di sini kami menentukan perkara yang perlu dilakukan dengan setiap fail dalam setiap direktori. Jika anda memerlukan logik yang lebih kompleks untuk melintasi struktur fail, anda harus menulis pelaksanaan anda sendiri FileVisitor. Anda perlu melaksanakan 3 lagi kaedah dalam kelas itu:
  • preVisitDirectory(): logik untuk dilaksanakan sebelum memasuki folder;

  • visitFileFailed(): logik untuk dilaksanakan jika fail tidak boleh dilawati (tiada akses, atau atas sebab lain);

  • postVisitDirectory(): logik untuk dilaksanakan selepas memasuki folder.

Kami tidak memerlukan sebarang logik sedemikian dilaksanakan, jadi kami baik-baik saja dengan SimpleFileVisitor. Logik di dalam visitFile()kaedah ini agak mudah: baca semua baris dalam fail, semak sama ada ia mengandungi kandungan yang kami perlukan, dan jika ya, cetak laluan mutlak pada konsol. Satu-satunya baris yang mungkin menyebabkan anda kesukaran ialah yang ini:
return FileVisitResult.CONTINUE;
Sebenarnya, ini sangat mudah. Di sini kami hanya menerangkan perkara yang perlu dilakukan oleh program selepas fail dilawati dan semua operasi yang diperlukan telah dilakukan. Dalam kes kami, kami mahu terus melintasi pokok itu, jadi kami memilih CONTINUEpilihan. Tetapi, sebagai alternatif, kami mungkin mempunyai objektif yang berbeza: daripada mencari semua fail yang mengandungi "Ini ialah fail yang kami perlukan", cari hanya satu fail sedemikian . Selepas itu, program harus ditamatkan. Dalam kes ini, kod kami akan kelihatan sama, tetapi bukannya pecah akan ada:
return FileVisitResult.TERMINATE;
Baiklah, mari jalankan kod kami dan lihat sama ada ia berfungsi.
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());
   }
}
Output 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
Cemerlang! Ianya berhasil! :) Anda juga boleh menerima cabaran kecil ini: gantikan SimpleFileVisitordengan yang biasa FileVisitor, ganti semua 4 kaedah dan tentukan tujuan anda sendiri untuk program ini. Sebagai contoh, anda boleh menulis program yang merekodkan semua tindakannya: paparkan nama fail atau folder sebelum atau selepas memasukkannya. Itu sahaja buat masa ini. Jumpa lagi! :)
Komen
  • Popular
  • Baru
  • Tua
Anda mesti log masuk untuk meninggalkan ulasan
Halaman ini tidak mempunyai sebarang ulasan lagi