Lớp Files
(Class Files)

Lớp Files trong gói java.nio.file là trung tâm chính cho việc thao tác với tệp và thư mục trong Java. Nó cung cấp một tập hợp phong phú các phương thức tĩnh (static methods) để đọc, ghi, sao chép, di chuyển, xóa, và truy vấn tệp và thư mục. Các phương thức của lớp Files làm việc với các đối tượng Path để thực hiện nhiều thao tác với tệp một cách hiệu quả và tin cậy.

Trước khi tìm hiểu về các phương thức cụ thể, bạn nên hiểu một số khái niệm và thực hành cơ bản liên quan đến các thao tác với tệp:

(1) Giải phóng tài nguyên hệ thống (Releasing System Resources)

Nhiều tài nguyên được sử dụng trong API này, chẳng hạn như các luồng (stream) hoặc kênh (channel), đều triển khai hoặc mở rộng giao diện java.io.Closeable. Yêu cầu của tài nguyên Closeable là phương thức close phải được gọi để giải phóng tài nguyên khi không còn cần thiết. Bỏ qua việc đóng một tài nguyên có thể ảnh hưởng tiêu cực đến hiệu suất của ứng dụng. Câu lệnh try-with-resources được mô tả trong phần tiếp theo sẽ tự động xử lý bước này cho bạn.

(2) Xử lý ngoại lệ (Catching Exceptions)

Trong I/O file, các điều kiện không mong đợi là điều thường gặp: file tồn tại (hoặc không tồn tại) khi mong đợi, chương trình không có quyền truy cập vào hệ thống file, triển khai hệ thống file mặc định không hỗ trợ một chức năng cụ thể, v.v. Có thể gặp nhiều lỗi.

Tất cả các phương thức truy cập hệ thống file đều có thể ném ra một ngoại lệ IOException. Cách thực hành tốt nhất là bắt các ngoại lệ này bằng cách nhúng các phương thức này vào một câu lệnh try-with-resources, được giới thiệu trong bản phát hành Java SE 7. Câu lệnh try-with-resources có ưu điểm là trình biên dịch tự động tạo mã để đóng tài nguyên khi không còn cần thiết. Mã sau đây cho thấy cách thực hiện:

Ví dụ

Charset charset = Charset.forName("US-ASCII");
String s = ...;
try (BufferedWriter writer = Files.newBufferedWriter(file, charset)) {
    writer.write(s, 0, s.length());
} catch (IOException x) {
    System.err.format("IOException: %s%n", x);
}

Ngoài ra, bạn cũng có thể đặt các phương thức thao tác với tệp trong một khối try và sau đó bắt bất kỳ ngoại lệ nào trong khối catch. Nếu mã của bạn đã mở bất kỳ luồng hoặc kênh nào, bạn nên đóng chúng trong khối finally. Ví dụ trước sẽ trông như sau khi sử dụng cách tiếp cận try-catch-finally:

Ví dụ

Charset charset = Charset.forName("US-ASCII");
String s = ...;
BufferedWriter writer = null;
try {
    writer = Files.newBufferedWriter(file, charset);
    writer.write(s, 0, s.length());
} catch (IOException x) {
    System.err.format("IOException: %s%n", x);
} finally {
    if (writer != null) writer.close();
}

Ngoài IOException, còn nhiều ngoại lệ cụ thể mở rộng từ FileSystemException. Lớp này có một số phương thức hữu ích trả về tệp liên quan (phương thức getFile), chuỗi thông báo chi tiết (getMessage), lý do tại sao thao tác hệ thống tệp thất bại (getReason), và tệp "khác" liên quan (nếu có) (getOtherFile).

Ví dụ đoạn mã sau đây cho thấy cách sử dụng phương thức getFile:

Ví dụ

try (...) {
    ...    
} catch (NoSuchFileException x) {
    System.err.format("%s does not exist\n", x.getFile());
}

(3) Đối số biến đổi (Varargs)

Một số phương thức trong lớp Files chấp nhận một số lượng đối số tùy ý khi các cờ (flags) được chỉ định. Ví dụ, trong chữ ký phương thức dưới đây, ký hiệu ba chấm sau đối số CopyOption cho biết phương thức này chấp nhận một số lượng đối số biến đổi, thường được gọi là varargs:

Ví dụ

Path Files.move(Path, Path, CopyOption...)

Khi một phương thức chấp nhận đối số varargs, bạn có thể truyền cho nó một danh sách giá trị ngăn cách bằng dấu phẩy hoặc một mảng các giá trị (ví dụ, CopyOption[]).

Trong ví dụ move, phương thức này có thể được gọi như sau:

Ví dụ

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

Path source = ...;
Path target = ...;
Files.move(source,
           target,
           REPLACE_EXISTING,
           ATOMIC_MOVE);

(4) Các thao tác nguyên tử (Atomic Operations)

Một số phương thức trong lớp Files, như move, có thể thực hiện một số thao tác nhất định theo cách nguyên tử trên một số hệ thống tệp.

Một thao tác nguyên tử là một thao tác không thể bị gián đoạn hoặc thực hiện "một phần". Hoặc toàn bộ thao tác được thực hiện, hoặc thao tác thất bại. Điều này quan trọng khi bạn có nhiều tiến trình hoạt động trên cùng một khu vực của hệ thống tệp, và bạn cần đảm bảo rằng mỗi tiến trình truy cập vào một tệp hoàn chỉnh.

Trong ví dụ trên, ATOMIC_MOVE đảm bảo rằng việc di chuyển tệp là một thao tác nguyên tử, không bị gián đoạn bởi các tiến trình khác.

(5) Phương pháp gọi chuỗi (Method Chaining)

Phương pháp chaining cho phép bạn gọi nhiều phương thức liên tiếp mà không cần phải sử dụng các biến tạm thời. Điều này làm cho mã nguồn trở nên gọn gàng hơn và dễ đọc hơn. Ví dụ:

Ví dụ

String value = Charset.defaultCharset().decode(buf).toString();
UserPrincipal group = 
    file.getFileSystem().getUserPrincipalLookupService()
        .lookupPrincipalByName("me");

Phương pháp này giúp mã nguồn trở nên ngắn gọn và loại bỏ sự cần thiết phải khai báo các biến tạm thời không cần thiết.

(6) Glob là gì?

Hai phương thức trong lớp Files chấp nhận một đối số glob, nhưng glob là gì?

Bạn có thể sử dụng cú pháp glob để chỉ định hành vi khớp mẫu.

Một glob là một mẫu ký tự dùng để so khớp tên tệp hoặc thư mục. Nó cho phép bạn chỉ định các mẫu để tìm kiếm tệp hoặc thư mục theo các quy tắc nhất định. Cú pháp glob tuân theo một số quy tắc đơn giản:

(1) Một dấu sao (*) khớp với bất kỳ số lượng ký tự nào (bao gồm không có ký tự).

(2) Hai dấu sao (**) hoạt động như *, nhưng có thể vượt qua ranh giới thư mục. Cú pháp này thường được sử dụng để khớp với toàn bộ đường dẫn.

(3) Dấu hỏi (?) khớp với chính xác một ký tự.

(4) Dấu ngoặc nhọn chỉ định một tập hợp các mẫu con. Ví dụ:

↳ {(sun, moon, stars)} khớp với "sun", "moon", hoặc "stars".

↳ {temp*,tmp*} khớp với tất cả các chuỗi bắt đầu bằng "temp" hoặc "tmp".

(5) Dấu ngoặc vuông truyền tải một tập hợp các ký tự đơn lẻ hoặc, khi sử dụng dấu gạch ngang (-), một phạm vi ký tự. Ví dụ:

↳ [aeiou] khớp với bất kỳ nguyên âm viết thường nào.

↳ [0-9] khớp với bất kỳ chữ số nào.

↳ [A-Z] khớp với bất kỳ chữ cái viết hoa nào.

↳ [a-z,A-Z] khớp với bất kỳ chữ cái viết hoa hoặc viết thường nào.

↳ Trong dấu ngoặc vuông, *, ?, và \ khớp chính chúng.

↳ Tất cả các ký tự khác khớp chính chúng.

Để khớp với *, ?, hoặc các ký tự đặc biệt khác, bạn có thể thoát chúng bằng cách sử dụng ký tự gạch chéo ngược (\). Ví dụ: \\ khớp với một gạch chéo ngược đơn, và \? khớp với dấu hỏi.

Dưới đây là một số ví dụ về cú pháp glob:

↳ *.html – Khớp với tất cả các chuỗi kết thúc bằng .html

↳ ??? – Khớp với tất cả các chuỗi có chính xác ba chữ cái hoặc chữ số

↳ *[0-9]* – Khớp với tất cả các chuỗi chứa giá trị số

↳ *.{htm,html,pdf} – Khớp với bất kỳ chuỗi nào kết thúc bằng .htm, .html, hoặc .pdf

↳ a?*.java – Khớp với bất kỳ chuỗi nào bắt đầu bằng a, theo sau là ít nhất một chữ cái hoặc chữ số, và kết thúc bằng .java

↳ {foo*,*[0-9]*} – Khớp với bất kỳ chuỗi nào bắt đầu bằng foo hoặc bất kỳ chuỗi nào chứa giá trị số

Lưu ý: Nếu bạn nhập mẫu glob từ bàn phím và nó chứa một trong những ký tự đặc biệt, bạn phải đặt mẫu trong dấu ngoặc kép ("*"), sử dụng gạch chéo ngược (*), hoặc sử dụng cơ chế thoát ký tự nào được hỗ trợ trên dòng lệnh.

Cú pháp glob rất mạnh mẽ và dễ sử dụng. Tuy nhiên, nếu nó không đáp ứng đủ yêu cầu của bạn, bạn có thể sử dụng biểu thức chính quy (regular expression). Để biết thêm thông tin, hãy tham khảo bài học về biểu thức chính quy.

(7) Nhận biết liên kết (Link Awareness)

Lớp Files có khả năng nhận biết liên kết (link awareness). Mỗi phương thức trong lớp Files hoặc tự động phát hiện và xử lý khi gặp liên kết tượng trưng (symbolic link), hoặc cung cấp một tùy chọn cho phép bạn cấu hình hành vi khi gặp phải liên kết tượng trưng. Điều này giúp bạn kiểm soát tốt hơn khi làm việc với hệ thống tệp chứa các liên kết.

Khai báo lớp Files trong Java

Để sử dụng lớp Files bạn cần import gói java.nio.file bạn cần thêm câu lệnh import vào đầu file Java của mình.

Cú pháp câu lệnh import:

Cú pháp

import java.nio.file.Files;

Cú pháp khai báo lớp Files:

Cú pháp

public final class Files
extends Object

Dưới đây là giải thích chi tiết về cú pháp khai báo này:

↳ public: Từ khóa này xác định rằng lớp Files có thể được truy cập từ bất kỳ đâu, không chỉ từ bên trong cùng một gói (package). Điều này có nghĩa là bất kỳ lớp nào trong ứng dụng, kể cả những lớp ở các gói khác nhau, đều có thể sử dụng lớp Files.

↳ final: Từ khóa final khi được sử dụng với một lớp có nghĩa là lớp này không thể bị kế thừa bởi bất kỳ lớp nào khác. Nói cách khác, không thể tạo một lớp con (subclass) từ lớp Files. Điều này thường được sử dụng để ngăn chặn sự thay đổi không mong muốn hoặc đảm bảo tính bảo mật cho lớp.

↳ class Files: Đây là định nghĩa lớp Files. Lớp này chứa các phương thức và thuộc tính liên quan đến việc làm việc với hệ thống tệp trong Java. Files là một lớp tiện ích trong gói java.nio.file, cung cấp các phương thức tĩnh để làm việc với các tệp và thư mục.

↳ extends Object: Từ khóa extends chỉ ra rằng lớp Files kế thừa từ lớp Object. Trong Java, mọi lớp đều mặc định kế thừa từ Object nếu không kế thừa từ lớp nào khác. Object là lớp cơ bản của tất cả các lớp trong Java, cung cấp các phương thức cơ bản như toString(), equals(), và hashCode().

Các phương thức tĩnh của lớp Files

Lớp Files cung cấp một loạt các phương thức tĩnh để thực hiện các hoạt động trên file và thư mục. Dưới đây là danh sách tất cả các phương thức của lớp Files trong Java:

Các phương thức trong Java dùng để tạo Files:

Phương thứcMô tả
static Path createDirectory(Path dir, FileAttribute<?>... attrs)Tạo một thư mục mới.
static Path createDirectories(Path dir, FileAttribute<?>... attrs)Tạo một thư mục và tất cả các thư mục cha cần thiết.
static Path createFile(Path path, FileAttribute<?>... attrs)Tạo một tệp tin mới và trống.
static Path createTempDirectory(Path dir, String prefix, FileAttribute<?>... attrs)Tạo một thư mục tạm thời trong thư mục đã chỉ định.
static Path createTempDirectory(String prefix, FileAttribute<?>... attrs)Tạo một thư mục tạm thời trong thư mục mặc định.
static Path createTempFile(Path dir, String prefix, String suffix, FileAttribute<?>... attrs)Tạo một tệp tin tạm thời trong thư mục đã chỉ định với tiền tố và hậu tố cho tên.
static Path createTempFile(String prefix, String suffix, FileAttribute<?>... attrs)Tạo một tệp tin tạm thời trong thư mục tạm thời mặc định với tiền tố và hậu tố cho tên.

Các phương thức trong Java dùng để đọc và ghi Files:

Phương thứcMô tả
static Stream<String> lines(Path path)Đọc tất cả các dòng từ một tệp tin dưới dạng một Stream.
static Stream<String> lines(Path path, Charset cs)Đọc tất cả các dòng từ một tệp tin với mã hóa ký tự đã chỉ định dưới dạng một Stream.
static BufferedReader newBufferedReader(Path path)Mở một tệp tin để đọc, trả về một BufferedReader để đọc văn bản hiệu quả.
static BufferedReader newBufferedReader(Path path, Charset cs)Mở một tệp tin để đọc với mã hóa ký tự đã chỉ định, trả về BufferedReader.
static BufferedWriter newBufferedWriter(Path path, Charset cs, OpenOption... options)Mở hoặc tạo một tệp tin để ghi với mã hóa ký tự đã chỉ định, trả về BufferedWriter.
static BufferedWriter newBufferedWriter(Path path, OpenOption... options)Mở hoặc tạo một tệp tin để ghi, trả về BufferedWriter.
static SeekableByteChannel newByteChannel(Path path, OpenOption... options)Mở hoặc tạo một tệp tin, trả về một kênh byte có thể tìm kiếm để truy cập tệp tin.
static SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs)Mở hoặc tạo một tệp tin với tùy chọn và thuộc tính bổ sung, trả về một kênh byte.
static InputStream newInputStream(Path path, OpenOption... options)Mở một tệp tin để đọc, trả về một InputStream.
static OutputStream newOutputStream(Path path, OpenOption... options)Mở hoặc tạo một tệp tin để ghi, trả về một OutputStream.
static byte[] readAllBytes(Path path)Đọc tất cả các byte từ một tệp tin và trả về một mảng byte.
static List<String> readAllLines(Path path)Đọc tất cả các dòng từ một tệp tin và trả về danh sách các chuỗi.
static List<String> readAllLines(Path path, Charset cs)Đọc tất cả các dòng từ một tệp tin với mã hóa ký tự đã chỉ định và trả về danh sách chuỗi.
static Path write(Path path, byte[] bytes, OpenOption... options)Ghi một mảng byte vào tệp tin.
static Path write(Path path, Iterable<? extends CharSequence> lines, Charset cs, OpenOption... options)Ghi một danh sách các dòng văn bản vào tệp tin với mã hóa ký tự đã chỉ định.
static Path write(Path path, Iterable<? extends CharSequence> lines, OpenOption... options)Ghi một danh sách các dòng văn bản vào file.

Các phương thức trong Java dùng để tạo và đọc thư mục:

Phương thứcMô tả
static Stream<Path> list(Path dir)Trả về một Stream các Path đại diện cho các mục trong thư mục.
static DirectoryStream<Path> newDirectoryStream(Path dir)Mở một thư mục, trả về một DirectoryStream để duyệt qua các mục trong thư mục.
static DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter)Mở một thư mục, trả về một DirectoryStream để duyệt qua các mục trong thư mục với bộ lọc.
static DirectoryStream<Path> newDirectoryStream(Path dir, String glob)Mở một thư mục, trả về DirectoryStream để lặp lại các mục trong thư mục theo mẫu glob.

Các phương thức trong Java dùng để sao chép Files:

Phương thứcMô tả
static long copy(InputStream in, Path target, CopyOption... options)Sao chép tất cả các byte từ một luồng đầu vào vào một file.
static long copy(Path source, OutputStream out)Sao chép tất cả các byte từ một file vào một luồng đầu ra.
static long copy(Path source, Path target, CopyOption... options)Sao chép một file sang một file đích.

Các phương thức trong Java dùng để di chuyển Files:

Phương thứcMô tả
static Path move(Path source, Path target, CopyOption... options)Di chuyển hoặc đổi tên một file sang một file đích.

Các phương thức trong Java dùng để kiểm tra Files:

Phương thứcMô tả
static boolean exists(Path path, LinkOption... options)Kiểm tra sự tồn tại của một file, có thể sử dụng các tùy chọn LinkOption để xử lý liên kết tượng trưng.
static boolean notExists(Path path, LinkOption... options)Kiểm tra xem một file không tồn tại.
static boolean isReadable(Path path)Kiểm tra xem một file có thể đọc được hay không.
static boolean isWritable(Path path)Kiểm tra xem một file có thể ghi được hay không.
static boolean isExecutable(Path path)Kiểm tra xem một file có thể thực thi được hay không.
static boolean isSameFile(Path path, Path path2)Kiểm tra xem hai đường dẫn chỉ đến cùng một file hay không.

Các phương thức trong Java dùng để xóa Files:

Phương thứcMô tả
static void delete(Path path)Xóa một file.
static boolean deleteIfExists(Path path)Xóa một file nếu nó tồn tại, trả về true nếu xóa thành công, false nếu file không tồn tại.

Các phương thức trong Java dùng để duyệt cây thư mục:

Phương thứcMô tả
static Stream<Path> find(Path start, int maxDepth, BiPredicate<Path,BasicFileAttributes> matcher, FileVisitOption... options)Tìm kiếm các file trong một cây thư mục theo các điều kiện đã cho, trả về một Stream các Path.
static Stream<Path> walk(Path start, FileVisitOption... options)Trả về một Stream các Path bằng cách duyệt cây thư mục bắt đầu từ một file.
static Stream<Path> walk(Path start, int maxDepth, FileVisitOption... options)Trả về một Stream các Path bằng cách duyệt cây thư mục bắt đầu từ một file với độ sâu tối đa.
static Path walkFileTree(Path start, FileVisitor<? super Path> visitor)Duyệt cây thư mục bằng cách sử dụng một FileVisitor.
static Path walkFileTree(Path start, Set<FileVisitOption> options, int maxDepth, FileVisitor<? super Path> visitor)Duyệt cây thư mục với các tùy chọn bổ sung và độ sâu tối đa.

Các phương thức trong Java dùng để quản lý siêu dữ liệu (Managing Metadata):

Phương thứcMô tả
static long size(Path)Trả về kích thước của tệp được chỉ định tính bằng byte.
static boolean isDirectory(Path, LinkOption...)Trả về true nếu Path chỉ định một thư mục.
static boolean isRegularFile(Path, LinkOption...)Trả về true nếu Path chỉ định một tệp bình thường.
static boolean isSymbolicLink(Path)Trả về true nếu Path chỉ định một liên kết biểu tượng.
static boolean isHidden(Path)Trả về true nếu Path chỉ định một tệp ẩn.
static FileTime getLastModifiedTime(Path, LinkOption...)Trả về thời gian sửa đổi cuối cùng của tệp.
static Path setLastModifiedTime(Path, FileTime)Đặt thời gian sửa đổi cuối cùng của tệp.
static UserPrincipal getOwner(Path, LinkOption...)Trả về chủ sở hữu của tệp.
static Path setOwner(Path, UserPrincipal)Đặt chủ sở hữu của tệp.
static Set<PosixFilePermission> getPosixFilePermissions(Path, LinkOption...)Trả về quyền truy cập POSIX của tệp.
static Path setPosixFilePermissions(Path, Set<PosixFilePermission>)Đặt quyền truy cập POSIX của tệp.
static Object getAttribute(Path, String, LinkOption...)Trả về giá trị của một thuộc tính tệp.
static Path setAttribute(Path, String, Object, LinkOption...)Đặt giá trị của một thuộc tính tệp.
static Map<String, Object> readAttributes(Path, String, LinkOption...)Đọc thuộc tính của tệp dưới dạng một thao tác khối.
static <A extends BasicFileAttributes> A readAttributes(Path, Class<A>, LinkOption...)Đọc thuộc tính của tệp dưới dạng một đối tượng.
static <V extends FileAttributeView>V getFileAttributeView(Path path, Class<V> type, LinkOption... options)Trả về một view của các thuộc tính của file theo một kiểu cụ thể.
static FileStore getFileStore(Path path)Trả về đối tượng FileStore đại diện cho nơi lưu trữ của file.

Các phương thức trong Java dùng để quản lý liên kết Files (Links Files):

Phương thứcMô tả
static Path createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)Tạo một liên kết tượng trưng (symbolic link) đến một mục tiêu, với các thuộc tính tùy chọn.
static Path createLink(Path link, Path existing)Tạo một liên kết cứng (hard link) đến một tệp tin hiện có.
static boolean isSymbolicLink(Path)Trả về true nếu Path chỉ định một liên kết tượng trưng.
static Path readSymbolicLink(Path link)Đọc và trả về mục tiêu của một liên kết tượng trưng.

Các phương thức trong Java dùng để xác định loại MIME Files:

Phương thứcMô tả
static String probeContentType(Path path)Xác định loại nội dung của một file.

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.”