Đọc Thư Mục
(Reading Directory)

Trong Java, việc đọc nội dung của thư mục là một thao tác quan trọng khi làm việc với hệ thống tệp. Lớp Files trong gói java.nio.file cung cấp nhiều phương thức hỗ trợ, từ liệt kê các thư mục gốc của hệ thống tệp đến lọc nội dung bằng cú pháp globbing hoặc tạo bộ lọc tùy chỉnh. Bài viết này sẽ hướng dẫn bạn cách thực hiện những thao tác này một cách đơn giản và hiệu quả.

(1) Liệt kê các thư mục gốc của hệ thống tệp

Bạn có thể liệt kê tất cả các thư mục gốc của hệ thống tệp bằng cách sử dụng phương thức FileSystem.getRootDirectories(). Phương thức này trả về một Iterable, cho phép bạn sử dụng vòng lặp for để lặp qua tất cả các thư mục gốc.

Dưới đây là ví dụ mã nguồn để in các thư mục gốc của hệ thống tệp mặc định:

Ví dụ: Example.java

import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;

public class Example {
    public static void main(String[] args) {
        // Lấy hệ thống tệp mặc định
        FileSystem fileSystem = FileSystems.getDefault();

        // Liệt kê tất cả các thư mục gốc
        Iterable<Path> rootDirectories = fileSystem.getRootDirectories();

        // In tất cả các thư mục gốc
        System.out.println("Các thư mục gốc của hệ thống tệp:");
        for (Path root : rootDirectories) {
            System.out.println(root);
        }
    }
}

Kết quả của chương trình là:

Các thư mục gốc của hệ thống tệp:
C:\
D:\
E:\

Lưu ý:

↳ Trên Windows, kết quả có thể là C:\ và D:\, nếu có nhiều phân vùng.

↳ Trên Unix hoặc Linux, kết quả thường là /, vì Unix/Linux thường có một thư mục gốc duy nhất.

↳ Đoạn mã này giúp bạn nhanh chóng kiểm tra các thư mục gốc có sẵn trên hệ thống của bạn.

(2) Liệt kê nội dung của một thư mục

Để liệt kê tất cả các mục trong một thư mục, bạn có thể sử dụng phương thức Files.newDirectoryStream(Path). Phương thức này trả về một đối tượng triển khai giao diện DirectoryStream. Giao diện DirectoryStream cũng triển khai Iterable, cho phép bạn lặp qua các mục trong thư mục. Cách tiếp cận này hoạt động tốt cho các thư mục rất lớn.

Lưu ý: Đối tượng DirectoryStream là một luồng. Nếu bạn không sử dụng câu lệnh try-with-resources, hãy đảm bảo đóng luồng trong khối finally. Câu lệnh try-with-resources sẽ tự động xử lý việc này cho bạn.

Dưới đây là một ví dụ mã nguồn về cách in nội dung của một thư mục:

Ví dụ: Example.java

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.EnumSet;

public class Example {
    public static void main(String[] args) {
        // Đường dẫn đến thư mục cần liệt kê nội dung
        Path directoryPath = Paths.get("D:\\baitapjava\\studyone");

        // Liệt kê nội dung của thư mục
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath)) {
            for (Path entry : stream) {
                System.out.println(entry.getFileName());
            }
        } catch (IOException e) {
            System.err.format("IOException: %s%n", e);
        }
        
        // Nếu bạn muốn duyệt tất cả các tệp và thư mục con, bao gồm cả thư mục con trong thư mục
        try {
            Files.walkFileTree(directoryPath, EnumSet.noneOf(FileVisitOption.class), Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    System.out.println("File: " + file);
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    System.out.println("Directory: " + dir);
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            System.err.format("IOException: %s%n", e);
        }
    }
}

Kết quả của chương trình là:

homework.java
readaudio.java
study2.java
study3.java
File: D:\baitapjava\studyone\homework.java
File: D:\baitapjava\studyone\readaudio.java
File: D:\baitapjava\studyone\study2.java
File: D:\baitapjava\studyone\study3.java
Directory: D:\baitapjava\studyone

Đối với ví dụ đầu tiên, bạn sẽ chỉ nhận được danh sách các tệp và thư mục trong thư mục gốc được chỉ định.

Đối với ví dụ thứ hai, bạn sẽ nhận được danh sách đầy đủ tất cả các tệp và thư mục, bao gồm cả các thư mục con, từ thư mục gốc được chỉ định.

(3) Lọc danh sách thư mục bằng cú pháp Globbing

Để lọc danh sách thư mục và chỉ lấy các tệp và thư mục con phù hợp với một mẫu cụ thể, bạn có thể sử dụng phương thức Files.newDirectoryStream(Path, String) với cú pháp glob. Điều này cho phép bạn chỉ định các mẫu cho tên tệp, giúp dễ dàng lấy được các tệp liên quan.

Ví dụ: Liệt kê các tệp liên quan đến Java

Đoạn mã sau đây minh họa cách liệt kê các tệp trong một thư mục phù hợp với các mẫu cụ thể (ví dụ: tệp .class, .java, và .jar):

Ví dụ: Example.java

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

public class Example {

    public static void main(String[] args) {
        Path dir = Paths.get("D:\\baitapjava\\study"); // Thay thế bằng đường dẫn thư mục của bạn

        // Định nghĩa mẫu glob để phù hợp với các tệp .java, .class, và .jar
        String globPattern = "*.{java,class,jar}";

        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, globPattern)) {
            for (Path entry : stream) {
                System.out.println(entry.getFileName());
            }
        } catch (IOException x) {
            // IOException chỉ có thể được ném ra bởi newDirectoryStream
            System.err.println("Ngoại lệ: " + x);
        }
    }
}

Đoạn mã sẽ liệt kê tất cả các tệp trong thư mục phù hợp với từng mẫu glob: .class, .java, và .jar. Đầu ra có thể trông giống như sau:

study2.jar
study3.class
tudy1.java

Lưu Ý: Khi sử dụng các mẫu glob, hãy đảm bảo mẫu được chỉ định đúng và khớp với các loại tệp bạn muốn. Đối với lọc phức tạp hơn, hãy xem xét sử dụng biểu thức chính quy nếu mẫu glob không đủ.

(4) Viết bộ lọc thư mục tùy chỉnh

Nếu bạn muốn lọc nội dung của một thư mục dựa trên điều kiện khác ngoài việc khớp mẫu, bạn có thể tạo bộ lọc của riêng mình bằng cách triển khai giao diện DirectoryStream.Filter<T> . Giao diện này bao gồm một phương thức accept, phương thức này xác định liệu một tệp có thỏa mãn yêu cầu tìm kiếm hay không.

Ví dụ: Triển khai bộ lọc chỉ lấy các thư mục

Dưới đây là một đoạn mã ví dụ minh họa cách triển khai bộ lọc chỉ lấy các thư mục:

Ví dụ: Example.java

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

public class Example {
    public static void main(String[] args) {
        // Đường dẫn đến thư mục cần lọc
        Path directoryPath = Paths.get("D:\\baitapjava");// Thay thế bằng đường dẫn thư mục của bạn

        // Tạo bộ lọc chỉ lấy các thư mục
        DirectoryStream.Filter<Path> directoryFilter = new DirectoryStream.Filter<>() {
            @Override
            public boolean accept(Path entry) throws IOException {
                return Files.isDirectory(entry); // Chỉ chấp nhận thư mục
            }
        };

        // Liệt kê các thư mục phù hợp với bộ lọc
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath, directoryFilter)) {
            System.out.println("Thư mục trong đường dẫn đã chỉ định:");
            for (Path entry : stream) {
                System.out.println(entry.getFileName());
            }
        } catch (IOException e) {
            System.err.format("IOException: %s%n", e);
        }
    }
}

Đoạn mã này sẽ liệt kê tất cả các thư mục trong thư mục được chỉ định, và chỉ các thư mục sẽ được in ra. Đầu ra có thể trông giống như sau:

Thư mục trong đường dẫn đã chỉ định:
baitap
maypackage
mypackage1
Package1
study

Bằng cách này, bạn có thể tùy chỉnh bộ lọc để chỉ lấy các mục đáp ứng các điều kiện cụ thể của bạn.

Lưu ý về bộ lọc đơn thư mục: Phương pháp này chỉ lọc một thư mục cụ thể. Nếu bạn cần tìm tất cả các thư mục con trong một cây thư mục, bạn nên sử dụng cơ chế Duyệt Cây Tệp (Walking the File Tree).

Hy vọng rằng qua các ví dụ trên, bạn sẽ hiểu rõ hơn về cách đọc thư mục 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.”