CodeGym /จาวาบล็อก /สุ่ม /ไฟล์ Java, เส้นทาง
John Squirrels
ระดับ
San Francisco

ไฟล์ Java, เส้นทาง

เผยแพร่ในกลุ่ม
สวัสดี! วันนี้เราจะพูดถึงการทำงานกับไฟล์และไดเร็กทอรี คุณรู้วิธีจัดการเนื้อหาไฟล์แล้ว: เราได้ทุ่มเทบทเรียนมากมายให้กับสิ่งนี้ :) ฉันคิดว่าคุณพบว่ามันง่ายที่จะจำคลาสสองสามคลาสที่ใช้สำหรับจุดประสงค์เหล่านี้ ในบทเรียนวันนี้ เราจะพูดถึงการจัดการไฟล์โดยเฉพาะ: การสร้าง การเปลี่ยนชื่อ ฯลฯ ก่อน Java 7 การดำเนินการดังกล่าวทั้งหมดดำเนินการโดยใช้คลาสไฟล์ คุณสามารถอ่านได้ที่นี่ แต่ใน Java 7 ผู้สร้างภาษาตัดสินใจที่จะเปลี่ยนวิธีที่เราทำงานกับไฟล์และไดเร็กทอรี สิ่งนี้เกิดขึ้นเนื่องจาก คลาส Fileมีข้อบกพร่องหลายประการ ตัวอย่างเช่น ไม่มี เมธอด copy()ซึ่งจะให้คุณคัดลอกไฟล์จากที่หนึ่งไปยังอีกที่หนึ่งได้ (เป็นความสามารถที่จำเป็นอย่างยิ่ง) นอกจากนี้คลาส ไฟล์มีเมธอดค่อนข้างน้อยที่ส่งคืนค่าบูลีน เมื่อมีข้อผิดพลาด เมธอดดังกล่าวจะส่งกลับค่าเท็จ ไม่มีข้อยกเว้น ทำให้ระบุข้อผิดพลาดและวินิจฉัยสาเหตุของข้อผิดพลาดได้ยากมาก แทนที่ คลาส File เดียว คลาส 3 คลาสปรากฏขึ้น: Paths , PathและFiles เอาตรงๆนะPathคือส่วนต่อประสาน ไม่ใช่คลาส มาดูกันว่าพวกมันแตกต่างกันอย่างไรและทำไมเราถึงต้องการพวกมัน เริ่มจากสิ่งที่ง่ายที่สุด: เส้นทาง

เส้นทาง

Pathsเป็นคลาสที่ง่ายมากด้วยเมธอดสแตติกเดียว: get( ) มันถูกสร้างขึ้นเพื่อรับ วัตถุ เส้นทางจากสตริงหรือ URI ที่ส่งผ่าน เท่านั้น ไม่มีฟังก์ชั่นอื่น ๆ นี่คือตัวอย่างในที่ทำงาน:

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คืออะไรและทำไมจึงจำเป็น :)

เส้นทาง

Pathโดยทั่วไปแล้วเป็นอะนาล็อกที่ออกแบบใหม่ของคลาสFile ใช้งานได้ง่ายกว่าFile มาก ขั้นแรกนำเมธอดยูทิลิตี้ (สแตติก) จำนวนมากออกและย้ายไปที่คลาส ไฟล์ ประการที่สองคำสั่งถูกกำหนดให้กับค่าส่งคืนของเมธอดของอินเทอร์เฟซพาธ ในคลาสFileเมธอดจะคืนค่าเป็นStringหรือบูลีนหรือFile มันไม่ง่ายเลยที่จะคิดออก ตัวอย่างเช่น มี เมธอด getParent()ที่ส่งคืนสตริงที่แสดงพาธพาเรนต์ของไฟล์ปัจจุบัน แต่ก็มีกเมธอด getParentFile()ซึ่งส่งคืนสิ่งเดียวกันแต่อยู่ในรูปของ วัตถุ ไฟล์ ! เห็นได้ชัดว่าซ้ำซ้อน ดังนั้น ในอินเทอร์เฟซ Path เมธอด getParent()และเมธอดอื่นๆ สำหรับการทำงานกับไฟล์เพียงแค่ส่งคืนออบเจกต์พาธ ไม่มีตัวเลือกมากมาย — ทุกอย่างง่ายและเรียบง่าย Path มี วิธีการที่เป็นประโยชน์อะไรบ้าง? นี่คือบางส่วนและตัวอย่างวิธีการทำงาน:
  • getFileName() : ส่งคืนชื่อไฟล์จากเส้นทาง

  • getParent() : ส่งคืนไดเร็กทอรี "พาเรนต์" ของพาธปัจจุบัน (อีกนัยหนึ่ง ไดเร็กทอรีที่อยู่ด้านบนสุดของไดเร็กทอรีทรี);

  • getRoot() : ส่งคืนไดเร็กทอรี "root" เช่นไดเร็กทอรีที่อยู่ด้านบนสุดของแผนผังไดเร็กทอรี

  • startWith() , endsWith() : ตรวจสอบว่าเส้นทางเริ่มต้น/สิ้นสุดด้วยเส้นทางที่ผ่าน:

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

    เอาต์พุตคอนโซล:

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

    ให้ความสนใจกับวิธีการทำงานของendWith() จะตรวจสอบว่าเส้นทางปัจจุบันลงท้ายด้วยเส้นทาง ที่ผ่าน หรือไม่ โดยเฉพาะไม่ว่าจะอยู่ในเส้นทางไม่ใช่ในสตริงที่ผ่าน

    เปรียบเทียบผลลัพธ์ของการโทรทั้งสองนี้:

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

    เอาต์พุตคอนโซล:

    
    false
    true
    

    เมธอดendsWith()ต้องส่งผ่านพาธจริง ไม่ใช่แค่ชุดของอักขระ มิฉะนั้น ผลลัพธ์จะเป็นเท็จเสมอ แม้ว่าพาธปัจจุบันจะลงท้ายด้วยลำดับอักขระนั้นจริง ๆ (เช่นในกรณีของ "estFile.txt " ในตัวอย่างด้านบน).

    นอกจากนี้Path ยัง มีกลุ่มของเมธอดที่ทำให้การทำงานกับพาธสัมบูรณ์ (เต็ม) และสัมพัทธ์ง่ายขึ้น

ลองดูวิธีการเหล่านี้:
  • บูลีนisAbsolute()คืนค่าจริงหากเส้นทางปัจจุบันเป็นแบบสัมบูรณ์:

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

    เอาต์พุตคอนโซล:

    
    true
    
  • Path normalize() : "ทำให้ปกติ" เส้นทางปัจจุบัน ลบองค์ประกอบที่ไม่จำเป็นออกจากเส้นทาง คุณอาจรู้ว่าในระบบปฏิบัติการยอดนิยม สัญลักษณ์ "." (ไดเร็กทอรีปัจจุบัน) และ ".." (ไดเร็กทอรีหลัก) มักจะใช้เพื่อกำหนดพาธ ตัวอย่างเช่น " ./Pictures/dog.jpg " หมายความว่าไดเร็กทอรีปัจจุบันมีโฟลเดอร์ "Pictures" ซึ่งจะมีไฟล์ "dog.jpg"

    ดูนี่. หากเส้นทางใช้ "." หรือ ".." ปรากฏในโปรแกรมของคุณ เมธอด normalize()จะลบออกและสร้างพาธที่ไม่มี:

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

    เอาต์พุตคอนโซล:

    
    C:\Users\Java\examples
    C:\Users\examples
    
  • Path relativize() : คำนวณเส้นทางสัมพัทธ์ระหว่างเส้นทางปัจจุบันและเส้นทางที่ผ่าน

    ตัวอย่างเช่น:

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

    เอาต์พุตคอนโซล:

    
    Username\Desktop\testFile.txt
    

รายการ เมธอด Path ทั้งหมด นั้นค่อนข้างยาว คุณสามารถค้นหาทั้งหมดได้ในเอกสารประกอบของ Oracle ตอนนี้เราจะพิจารณาFiles ต่อ ไป

ไฟล์

Filesเป็นคลาสยูทิลิตี้ที่เก็บเมธอดสแตติกที่นำมาจากคลาส File ไฟล์เปรียบได้กับ Arraysหรือ Collections ข้อแตกต่างคือทำงานกับไฟล์ ไม่ใช่อาร์เรย์หรือคอลเลกชั่น :) มันเน้นไปที่การจัดการไฟล์และไดเร็กทอรี การใช้เมธอดแบบสแตติกของ คลาส Filesเราสามารถสร้าง ลบ และย้ายไฟล์และไดเร็กทอรีได้ การดำเนินการเหล่านี้ดำเนินการโดยใช้เมธอด createFile() (สำหรับไดเร็กทอรี, createDirectory() ), move()และ delete() นี่คือวิธีใช้:

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")));
   }
}
ก่อนอื่นเราสร้างไฟล์ ( เมธอดFiles.createFile() ) บนเดสก์ท็อป จากนั้นเราสร้างโฟลเดอร์ในตำแหน่งเดียวกัน ( เมธอดFiles.createDirectory() ) หลังจากนั้น เราย้ายไฟล์ ( เมธอด Files.move() ) จากเดสก์ท็อปไปยังโฟลเดอร์ใหม่นี้ และในที่สุดเราก็ลบไฟล์ ( เมธอด Files.delete() ) เอาต์พุตคอนโซล:

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
บันทึก:เช่นเดียวกับเมธอดของPathอินเทอร์เฟซเมธอดต่างๆ ของFilesคลาสจะส่งคืนPathวัตถุ วิธีการส่วนใหญ่ของFilesคลาสยังใช้Pathวัตถุเป็นอินพุต วิธีการ นี้Paths.get()จะเป็นผู้ช่วยที่ซื่อสัตย์ของคุณ - ใช้มันให้เป็นประโยชน์ มีอะไรน่าสนใจอีกบ้างFiles? สิ่งที่Fileคลาสเก่าขาดคือcopy()วิธีการ! เราได้พูดคุยเกี่ยวกับเรื่องนี้ในตอนต้นของบทเรียนนี้ ถึงเวลาที่จะพบกับมันแล้ว!

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")));
   }
}
เอาต์พุตคอนโซล:

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
ตอนนี้คุณรู้วิธีคัดลอกไฟล์โดยทางโปรแกรมแล้ว! :) แน่นอนFilesคลาสนี้ไม่เพียงแต่ให้คุณจัดการไฟล์เท่านั้น แต่ยังทำงานกับเนื้อหาในนั้นได้อีกด้วย มันมีwrite()เมธอดสำหรับเขียนข้อมูลลงไฟล์ และ 3 เมธอดสำหรับอ่านข้อมูล: read(), readAllBytes(), และreadAllLines() เราจะลงรายละเอียดในอันสุดท้าย ทำไมถึงเป็นเช่นนั้น? เพราะมีประเภทผลตอบแทนที่น่าสนใจมาก: List<String>! นั่นคือมันส่งคืนรายการบรรทัดทั้งหมดในไฟล์ให้เรา แน่นอนว่าสิ่งนี้ทำให้สะดวกมากในการทำงานกับเนื้อหาของไฟล์ เนื่องจากไฟล์ทั้งหมด ทีละบรรทัด สามารถแสดงบนคอนโซลโดยใช้การวนซ้ำปกติได้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);
       }
   }
}
เอาต์พุตคอนโซล:

I still recall the wondrous moment: 
When you appeared before my sight, 
As though a brief and fleeting omen, 
Pure phantom in enchanting light.
สะดวกสุดๆ! :) ความสามารถนี้ปรากฏใน Java 7 Stream APIปรากฏใน Java 8 ซึ่งเพิ่มองค์ประกอบบางอย่างของการเขียนโปรแกรมการทำงานให้กับ Java รวมถึงความสามารถในการจัดการไฟล์ที่สมบูรณ์ยิ่งขึ้น ลองนึกภาพว่าเรามีงานต่อไปนี้: ค้นหาบรรทัดทั้งหมดที่ขึ้นต้นด้วยคำว่า "As" แปลงเป็น UPPERCASE และแสดงบนคอนโซล โซลูชันที่ใช้Filesคลาสจะมีลักษณะอย่างไรใน Java 7 สิ่งนี้:

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);
       }
   }
}
เอาต์พุตคอนโซล:

AS THOUGH A BRIEF AND FLEETING OMEN, 
PURE PHANTOM IN ENCHANTING LIGHT.
ภารกิจสำเร็จ แต่คุณไม่คิดหรือว่าสำหรับงานง่ายๆ เช่นนี้ โค้ดของเรากลายเป็น... การใช้ Stream API ของ Java 8 ทำให้โซลูชันดูสวยงามยิ่งขึ้น:

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);
   }
}
เราได้ผลลัพธ์เดียวกัน แต่มีรหัสน้อยกว่ามาก! ยิ่งไปกว่านั้น ไม่มีใครสามารถพูดได้ว่าเราสูญเสีย "ความสามารถในการอ่าน" ฉันคิดว่าคุณสามารถแสดงความคิดเห็นเกี่ยวกับโค้ดนี้ได้อย่างง่ายดาย แม้จะไม่คุ้นเคยกับ Stream API ก็ตาม กล่าวโดยย่อสตรีมคือลำดับขององค์ประกอบต่างๆ ซึ่งคุณสามารถดำเนินการต่างๆ ได้ เราได้รับ Stream object จากFiles.lines()เมธอด จากนั้นใช้ 3 ฟังก์ชันกับมัน:
  1. เราใช้filter()วิธีเลือกเฉพาะบรรทัดจากไฟล์ที่ขึ้นต้นด้วย "As"

  2. เราดำเนินการผ่านบรรทัดที่เลือกทั้งหมดโดยใช้map()วิธีการและแปลงแต่ละบรรทัดเป็นตัวพิมพ์ใหญ่

  3. เราใช้collect()วิธีการรวบรวมบรรทัดที่ได้รับทั้งหมดเป็นList.

เราได้ผลลัพธ์เดียวกัน:

AS THOUGH A BRIEF AND FLEETING OMEN, 
PURE PHANTOM IN ENCHANTING LIGHT.
ทีนี้กลับมาที่ขนมปังและ เนย ของเรานั่นคือไฟล์ :) ความสามารถสุดท้ายที่เราจะพิจารณาในวันนี้คือการอธิบายโครงสร้างไฟล์ ในระบบปฏิบัติการสมัยใหม่ โครงสร้างไฟล์ส่วนใหญ่มักจะดูเหมือนต้นไม้: มีรากและมีกิ่ง ซึ่งสามารถมีกิ่งอื่นๆ เป็นต้น รากและกิ่งเป็นไดเร็กทอรี ตัวอย่างเช่น ไดเรกทอรี " С:// " อาจเป็นราก ประกอบด้วยสองสาขา: " C://Downloads " และ " C://Users " แต่ละสาขาเหล่านี้มีสองสาขา: " C://Downloads/Pictures ", " C://Downloads/Video ", " C://Users/JohnSmith ", " C://Users/Pudge2005" และสาขาเหล่านี้ก็มีสาขาอื่น ๆ เป็นต้น และนี่คือเหตุผลที่เราเรียกมันว่าต้นไม้ บน Linux โครงสร้างจะคล้ายกัน แต่ไดเร็กทอรี / เป็นรูท ตอนนี้ลองนึกภาพว่าเราต้องเริ่มที่ไดเร็กทอรี รูไฟล์ เส้นทาง - 2ท สำรวจโฟลเดอร์และโฟลเดอร์ย่อยทั้งหมด และค้นหาไฟล์ที่มีเนื้อหาเฉพาะ เราจะค้นหาไฟล์ที่มีบรรทัด "นี่คือไฟล์ที่เราต้องการ!" เราจะใช้โฟลเดอร์ "testFolder" ซึ่งอยู่บน เดสก์ท็อปเป็นไดเรกทอรีราก นี่คือเนื้อหา: ไฟล์ เส้นทาง - 3โฟลเดอร์ level1-a และ level1-b มีโฟลเดอร์ด้วย: ไฟล์ เส้นทาง - 4ไฟล์ เส้นทาง - 5ไม่มีโฟลเดอร์ใน "โฟลเดอร์ระดับที่สอง" เหล่านี้ มีเพียงไฟล์แต่ละไฟล์: ไฟล์ เส้นทาง - 6ไฟล์ เส้นทาง - 7ไฟล์ 3 ไฟล์ที่มีเนื้อหาที่เราต้องการนั้นจงใจให้ชื่ออธิบาย: FileWeNeed1.txt, FileWeNeed2.txt, FileWeNeed3.txt ไฟล์เหล่านี้เป็นไฟล์ที่เราต้องการค้นหาโดยใช้ Java เราจะทำเช่นนี้ได้อย่างไร? วิธีที่มีประสิทธิภาพมากในการข้ามแผนผังไฟล์มาช่วยเราFiles.walkFileTree (): นี่คือสิ่งที่เราต้องทำ อันดับแรก เราต้องมีFileVisitor. FileVisitorเป็นอินเตอร์เฟสพิเศษ ซึ่งอธิบายเมธอดสำหรับการข้ามทรีของไฟล์ โดยเฉพาะอย่างยิ่ง นั่นคือจุดที่เราจะใส่ตรรกะสำหรับการอ่านเนื้อหาของไฟล์และตรวจสอบว่ามีข้อความที่เราต้องการหรือไม่ นี่คือFileVisitorลักษณะของเรา:

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;
   }
}
ในกรณีนี้ คลาสของเราจะสืบทอดSimpleFileVisitor. นี่คือคลาสที่ใช้FileVisitorซึ่งเราจำเป็นต้องแทนที่เพียงหนึ่งเมธอด: visitFile(). ที่นี่เรากำหนดสิ่งที่ต้องทำกับแต่ละไฟล์ในแต่ละไดเร็กทอรี หากคุณต้องการตรรกะที่ซับซ้อนมากขึ้นสำหรับการสำรวจโครงสร้างไฟล์ คุณควรเขียนการใช้งานFileVisitor. คุณจะต้องใช้อีก 3 วิธีในคลาสนั้น:
  • preVisitDirectory(): ตรรกะที่จะดำเนินการก่อนเข้าสู่โฟลเดอร์

  • visitFileFailed(): ตรรกะในการดำเนินการหากไม่สามารถเยี่ยมชมไฟล์ได้ (ไม่มีการเข้าถึงหรือด้วยเหตุผลอื่น ๆ );

  • postVisitDirectory(): ตรรกะที่จะดำเนินการหลังจากเข้าสู่โฟลเดอร์

เราไม่จำเป็นต้องมีการดำเนินการตามตรรกะดังกล่าว ดังนั้นเราจึงไม่มีปัญหาSimpleFileVisitorกับ ตรรกะภายในvisitFile()เมธอดนั้นค่อนข้างง่าย: อ่านทุกบรรทัดในไฟล์ ตรวจดูว่ามีเนื้อหาที่เราต้องการหรือไม่ และถ้าใช่ ให้พิมพ์พาธสัมบูรณ์บนคอนโซล บรรทัดเดียวที่อาจทำให้คุณลำบากคือบรรทัดนี้:

return FileVisitResult.CONTINUE;
ที่จริงแล้วมันง่ายมาก ต่อไปนี้เป็นเพียงการอธิบายสิ่งที่โปรแกรมควรทำหลังจากไฟล์ถูกเยี่ยมชมและดำเนินการที่จำเป็นทั้งหมดแล้ว ในกรณีของเรา เราต้องการเดินทางข้ามต้นไม้ต่อไป เราจึงเลือกCONTINUEตัวเลือก แต่อีกทางหนึ่ง เราอาจมีวัตถุประสงค์อื่น: แทนที่จะค้นหาไฟล์ทั้งหมดที่มี "นี่คือไฟล์ที่เราต้องการ" ให้ค้นหาไฟล์ดังกล่าวเพียงไฟล์เดียว หลังจากนั้นโปรแกรมควรยุติ ในกรณีนี้ รหัสของเราจะมีลักษณะเหมือนกันทุกประการ แต่แทนที่จะเป็นตัวแบ่ง จะเป็น:

return FileVisitResult.TERMINATE;
ลองรันโค้ดของเราดูว่ามันใช้ได้ไหม

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());
   }
}
เอาต์พุตคอนโซล:

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
ยอดเยี่ยม! มันได้ผล! :) คุณยังสามารถยอมรับความท้าทายเล็กๆ น้อยๆ นี้: แทนที่SimpleFileVisitorด้วยวิธีธรรมดาFileVisitorลบล้างทั้ง 4 วิธี และกำหนดวัตถุประสงค์ของคุณเองสำหรับโปรแกรม ตัวอย่างเช่น คุณสามารถเขียนโปรแกรมที่บันทึกการทำงานทั้งหมด: แสดงชื่อไฟล์หรือโฟลเดอร์ก่อนหรือหลังการป้อน นั่นคือทั้งหมดที่สำหรับตอนนี้. แล้วพบกันใหม่! :)
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION