Tìm Kiếm Tệp Tin
(Finding Files)

Nếu bạn đã từng sử dụng script shell, có lẽ bạn đã quen với việc sử dụng khớp mẫu để tìm kiếm tệp. Việc này sử dụng các ký tự đặc biệt để tạo ra một mẫu và sau đó so sánh tên tệp với mẫu đó. Ví dụ, trong nhiều script shell, dấu hoa thị (*) khớp với bất kỳ số lượng ký tự nào. Ví dụ, lệnh sau liệt kê tất cả các tệp trong thư mục hiện tại kết thúc bằng .html:

Ví dụ lệnh

% ls *.html

(1) Tìm kiếm tệp tin bằng phương thức getPathMatcher(String)

Gói java.nio.file cung cấp hỗ trợ lập trình cho tính năng hữu ích này. Mỗi triển khai hệ thống tệp cung cấp một PathMatcher. Bạn có thể lấy PathMatcher của hệ thống tệp bằng cách sử dụng phương thức getPathMatcher(String) trong lớp FileSystem. Dưới đây là ví dụ về cách lấy PathMatcher và sử dụng nó để tìm kiếm tệp:

Ví dụ: Example.java

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

public class Example {
    public static void main(String[] args) {
        // Định nghĩa thư mục cần tìm kiếm và mẫu glob
        Path dir = Paths.get("path/to/your/directory");
        String pattern = "*.txt"; // Mẫu glob để tìm các tệp .txt

        // Lấy đối tượng PathMatcher từ FileSystem
        FileSystem fs = FileSystems.getDefault();
        PathMatcher matcher = fs.getPathMatcher("glob:" + pattern);

        try {
            // Duyệt qua các tệp trong thư mục
            Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    // Kiểm tra xem tệp có khớp với mẫu không
                    if (matcher.matches(file.getFileName())) {
                        System.out.println("Tệp khớp mẫu: " + file);
                    }
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            System.err.println("Lỗi khi duyệt thư mục: " + e.getMessage());
        }
    }
}

Ví dụ này cho thấy cách sử dụng PathMatcher để tìm kiếm các tệp dựa trên mẫu glob, giúp bạn lọc và xử lý tệp một cách hiệu quả hơn. Nếu bạn không quen với cú pháp glob, hãy xem Glob là gì.

Cú pháp glob dễ sử dụng và linh hoạt nhưng nếu thích, bạn cũng có thể sử dụng biểu thức chính quy hoặc cú pháp regex. Để biết thêm thông tin về regex, hãy xem bài họcJava Regex (Biểu thức chính quy) . Một số triển khai hệ thống tệp có thể hỗ trợ các cú pháp khác.

Cú pháp mẫu (Pattern Syntax)

↳ Glob Syntax: Cú pháp glob là cú pháp tìm kiếm tệp đơn giản và linh hoạt. Ví dụ: "*.java" khớp với tất cả các tệp có đuôi .java.

↳ Regex Syntax: Nếu bạn muốn sử dụng biểu thức chính quy, bạn có thể sử dụng cú pháp regex. Để làm điều này, thay đổi cú pháp mẫu thành "regex:" trong getPathMatcher.

(2) Tìm kiếm tệp đệ quy

Khi bạn cần tìm tệp phù hợp với một mẫu nhất định trong toàn bộ cây thư mục, việc đi qua cây thư mục (file tree traversal) là rất quan trọng. Ví dụ, bạn có thể biết rằng một tệp nào đó nằm ở đâu đó trong hệ thống tệp, nhưng bạn không chắc chắn vị trí chính xác, hoặc bạn có thể cần tìm tất cả các tệp trong cây thư mục có một phần mở rộng tệp cụ thể.

Ví dụ Find.java dưới đây sẽ giúp bạn thực hiện điều đó. Ví dụ này tương tự như tiện ích find trong UNIX nhưng có chức năng cơ bản hơn. Bạn có thể mở rộng ví dụ này để bao gồm các chức năng khác. Ví dụ, tiện ích find hỗ trợ cờ -prune để loại trừ toàn bộ cây con khỏi tìm kiếm. Bạn có thể thực hiện chức năng đó bằng cách trả về SKIP_SUBTREE trong phương thức preVisitDirectory. Để thực hiện tùy chọn -L, theo dõi liên kết biểu tượng, bạn có thể sử dụng phương thức walkFileTree với bốn tham số và truyền FOLLOW_LINKS enum (nhưng hãy đảm bảo kiểm tra các liên kết vòng trong phương thức visitFile).

Cách chạy ứng dụng Find.java

Để chạy ứng dụng Find, sử dụng cú pháp định dạng sau:

Cú pháp định dạng

% java Find <path> -name "<glob_pattern>"

Mẫu (pattern) cần được đặt trong dấu ngoặc kép để bất kỳ ký tự đại diện nào không bị shell giải thích. Ví dụ:

Ví dụ lệnh

% java Find . -name "*.html"

Dưới đây là mã nguồn cho ví dụ Find.java:

Dưới đây là đoạn mã Java dùng để tìm kiếm các tệp theo mẫu glob. Đoạn mã này sẽ tìm tất cả các tệp trong thư mục và các thư mục con của nó, khớp với mẫu glob được chỉ định, và in chúng ra màn hình. Nó cũng in ra tổng số tệp khớp với mẫu.

Ví dụ: Find.java

/**
 * Mẫu mã tìm kiếm các tệp khớp với mẫu glob được chỉ định.
 * Để biết thêm thông tin về mẫu glob, xem
 * https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob
 *
 * Các tệp hoặc thư mục khớp với mẫu sẽ được in ra
 * màn hình. Tổng số kết quả khớp cũng được in ra.
 *
 * Khi chạy ứng dụng này, bạn phải đưa mẫu glob vào trong dấu ngoặc kép,
 * để shell không mở rộng bất kỳ ký tự đại diện nào:
 *              java Find . -name "*.java"
 */

 import java.io.*;
 import java.nio.file.*;
 import java.nio.file.attribute.*;
 import static java.nio.file.FileVisitResult.*;
 import static java.nio.file.FileVisitOption.*;
 import java.util.*;
 
 public class Find {
 
     // Lớp phụ trợ để tìm kiếm các tệp khớp với mẫu glob
     public static class Finder extends SimpleFileVisitor<Path> {
 
         private final PathMatcher matcher;
         private int numMatches = 0;
 
         Finder(String pattern) {
             // Tạo PathMatcher với mẫu glob
             matcher = FileSystems.getDefault().getPathMatcher("glob:" + pattern);
         }
 
         // So sánh mẫu glob với tên tệp hoặc thư mục.
         void find(Path file) {
             Path name = file.getFileName();
             if (name != null && matcher.matches(name)) {
                 numMatches++;
                 System.out.println(file);
             }
         }
 
         // In tổng số kết quả khớp ra màn hình.
         void done() {
             System.out.println("Matched: " + numMatches);
         }
 
         // Gọi phương thức so sánh mẫu trên mỗi tệp.
         @Override
         public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
             find(file);
             return CONTINUE;
         }
 
         // Gọi phương thức so sánh mẫu trên mỗi thư mục.
         @Override
         public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
             find(dir);
             return CONTINUE;
         }
 
         @Override
         public FileVisitResult visitFileFailed(Path file, IOException exc) {
             System.err.println(exc);
             return CONTINUE;
         }
     }
 
     static void usage() {
         System.err.println("java Find <path> -name \"<glob_pattern>\"");
         System.exit(-1);
     }
 
     public static void main(String[] args) throws IOException {
 
         // Kiểm tra các tham số đầu vào
         if (args.length < 3 || !args[1].equals("-name"))
             usage();
 
         Path startingDir = Paths.get(args[0]);
         String pattern = args[2];
 
         // Khởi tạo Finder và bắt đầu tìm kiếm
         Finder finder = new Finder(pattern);
         Files.walkFileTree(startingDir, finder);
         finder.done();
     }
 }

Dưới đây là hướng dẫn chi tiết về cách thay thế đường dẫn:

↳ Khi chạy ứng dụng, bạn sẽ thay thế <path> và <glob_pattern> bằng giá trị thực tế.

↳ <path> là đường dẫn đến thư mục nơi bạn muốn bắt đầu tìm kiếm.

↳ <glob_pattern> là mẫu glob mà bạn muốn sử dụng để tìm kiếm.

Ví dụ:

Để tìm tất cả các tệp .java trong thư mục hiện tại:

Ví dụ lệnh

java Find . -name "*.java"

Để tìm tất cả các tệp .txt trong thư mục /home/user/documents:

Ví dụ lệnh

java Find /home/user/documents -name "*.txt"

Tìm tất cả các tệp .html trong thư mục /var/www và các thư mục con của nó:

Ví dụ lệnh

java Find /var/www -name "*.html"

Tìm tất cả các tệp có đuôi .class trong thư mục src:

Ví dụ lệnh

java Find src -name "*.class"

Hy vọng rằng qua các ví dụ trên, bạn sẽ hiểu rõ hơn về cách tạo tệp tin trong Java.

Câu Nói Truyền Cảm Hứng

“Bắt đầu ở đâu không quan trọng, quan trọng là bạn sẵn sàng bắt đầu.” – W. Clement Stone

Không Gian Tích Cực

“Chúc bạn luôn giữ vững niềm tin và sức mạnh để vượt qua mọi thử thách trong cuộc sống.”