1. Đọc thuộc tính cơ bản: BasicFileAttributes
Khi nói về một tệp hoặc thư mục, chúng ta không chỉ quan tâm đến tên hay kích thước. Mỗi tệp đều có “hộ chiếu” — một tập thuộc tính bao gồm:
- Thời gian tạo
- Thời gian sửa đổi gần nhất
- Thời gian truy cập gần nhất
- Kích thước
- Quyền truy cập (ai có thể đọc, ghi, thực thi)
- Thông tin về chủ sở hữu (trên Unix)
- Các cờ “ẩn”, “chỉ đọc” và khác
Trong Java, để làm việc với các thuộc tính này có một API tiện lợi và mạnh mẽ trong gói java.nio.file.attribute. Không cần viết mã phụ thuộc nền tảng: mọi thứ cần thiết đều có trong thư viện chuẩn.
Bắt đầu — nhập (import) các lớp cần thiết:
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.IOException;
Làm thế nào để lấy thuộc tính cơ bản của tệp?
Dùng phương thức Files.readAttributes:
Path path = Paths.get("example.txt");
try {
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
System.out.println("Tạo lúc: " + attrs.creationTime());
System.out.println("Sửa đổi lúc: " + attrs.lastModifiedTime());
System.out.println("Truy cập gần nhất: " + attrs.lastAccessTime());
System.out.println("Kích thước: " + attrs.size());
System.out.println("Là thư mục? " + attrs.isDirectory());
System.out.println("Là tệp thông thường? " + attrs.isRegularFile());
System.out.println("Là liên kết tượng trưng? " + attrs.isSymbolicLink());
} catch (IOException e) {
System.out.println("Lỗi khi đọc thuộc tính: " + e.getMessage());
}
Hãy hình dung bạn là người kiểm tra đến xem một căn hộ. Bạn không chỉ nhìn xem có cánh cửa (tệp tồn tại) hay không, mà còn hỏi cư dân: “Ngôi nhà xây khi nào? Lần sửa gần nhất là khi nào? Ai là chủ sở hữu?”.
Tóm tắt về các thuộc tính của BasicFileAttributes
| Thuộc tính | Trả về gì? |
|---|---|
|
Ngày giờ tạo tệp/thư mục |
|
Ngày giờ sửa đổi gần nhất |
|
Ngày giờ truy cập gần nhất |
|
Kích thước tệp (tính bằng byte) |
|
Có phải thư mục không? |
|
Có phải tệp thông thường không? |
|
Có phải liên kết tượng trưng không? |
2. Thuộc tính mở rộng: POSIX và DOS
Thuộc tính POSIX (Linux, macOS và các HĐH kiểu Unix khác)
Nếu bạn đang làm việc trên hệ Unix, có thể lấy thông tin mở rộng: quyền truy cập, chủ sở hữu, nhóm.
try {
PosixFileAttributes posixAttrs = Files.readAttributes(path, PosixFileAttributes.class);
System.out.println("Chủ sở hữu: " + posixAttrs.owner().getName());
System.out.println("Nhóm: " + posixAttrs.group().getName());
System.out.println("Quyền: " + PosixFilePermissions.toString(posixAttrs.permissions()));
} catch (UnsupportedOperationException e) {
System.out.println("Thuộc tính POSIX không được hỗ trợ trên HĐH này.");
} catch (IOException e) {
System.out.println("Lỗi khi đọc thuộc tính POSIX: " + e.getMessage());
}
Lưu ý: Trên Windows, đoạn mã này sẽ ném UnsupportedOperationException — điều đó là bình thường.
Thuộc tính DOS (Windows)
Trên Windows có thể làm việc với các cờ “chỉ đọc”, “ẩn”, “lưu trữ”, “hệ thống”:
try {
DosFileAttributes dosAttrs = Files.readAttributes(path, DosFileAttributes.class);
System.out.println("Ẩn: " + dosAttrs.isHidden());
System.out.println("Chỉ đọc: " + dosAttrs.isReadOnly());
System.out.println("Hệ thống: " + dosAttrs.isSystem());
System.out.println("Lưu trữ: " + dosAttrs.isArchive());
} catch (UnsupportedOperationException e) {
System.out.println("Thuộc tính DOS không được hỗ trợ trên HĐH này.");
} catch (IOException e) {
System.out.println("Lỗi khi đọc thuộc tính DOS: " + e.getMessage());
}
3. Thay đổi thuộc tính tệp
Đọc “hộ chiếu” là một chuyện, còn đổi ngày sinh hay họ tên lại là chuyện khác! Trong Java, chúng ta có thể thay đổi thuộc tính tệp (dĩ nhiên với quyền phù hợp).
Thay đổi thời gian sửa đổi gần nhất
import java.nio.file.attribute.FileTime;
Path file = Paths.get("example.txt");
try {
FileTime newTime = FileTime.fromMillis(System.currentTimeMillis() - 24 * 60 * 60 * 1000); // trừ 1 ngày
Files.setLastModifiedTime(file, newTime);
System.out.println("Đã thay đổi thời gian sửa đổi gần nhất!");
} catch (IOException e) {
System.out.println("Lỗi khi thay đổi thời gian: " + e.getMessage());
}
Thay đổi quyền truy cập (POSIX)
Chỉ dành cho hệ Unix! Ví dụ, đặt tệp thành có thể thực thi cho mọi người:
try {
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-xr-x");
Files.setPosixFilePermissions(file, perms);
System.out.println("Quyền đã được thay đổi!");
} catch (UnsupportedOperationException e) {
System.out.println("Quyền POSIX không được hỗ trợ trên HĐH này.");
} catch (IOException e) {
System.out.println("Lỗi khi thay đổi quyền: " + e.getMessage());
}
Giải thích chuỗi "rwxr-xr-x":
- r — read (đọc)
- w — write (ghi)
- x — execute (thực thi)
- Khối 3 ký tự đầu — chủ sở hữu; thứ hai — nhóm; thứ ba — những người còn lại.
Thay đổi trạng thái ẩn/chỉ đọc (thuộc tính DOS, Windows)
Đặt tệp thành ẩn:
try {
Files.setAttribute(file, "dos:hidden", true);
System.out.println("Tệp đã được đặt ẩn (Windows)!");
} catch (UnsupportedOperationException e) {
System.out.println("Thuộc tính DOS không được hỗ trợ trên HĐH này.");
} catch (IOException e) {
System.out.println("Lỗi khi thay đổi thuộc tính: " + e.getMessage());
}
Đặt tệp ở chế độ “chỉ đọc”:
try {
Files.setAttribute(file, "dos:readonly", true);
System.out.println("Tệp giờ ở chế độ chỉ đọc (Windows)!");
} catch (UnsupportedOperationException e) {
System.out.println("Thuộc tính DOS không được hỗ trợ trên HĐH này.");
} catch (IOException e) {
System.out.println("Lỗi khi thay đổi thuộc tính: " + e.getMessage());
}
4. Kiểm tra quyền truy cập
Đôi khi cần kiểm tra nhanh xem có thể mở tệp để đọc, ghi hoặc thực thi hay không:
Path file = Paths.get("example.txt");
System.out.println("Có thể đọc: " + Files.isReadable(file));
System.out.println("Có thể ghi: " + Files.isWritable(file));
System.out.println("Có thể thực thi: " + Files.isExecutable(file));
Điều này hoạt động giống nhau trên mọi nền tảng, dù hành vi thực tế phụ thuộc vào HĐH và cấu hình bảo mật.
5. Thực hành: in thông tin chi tiết về tệp
Viết một chương trình nhỏ, với đường dẫn tệp sẽ hiển thị tối đa thông tin và thử thay đổi một số thuộc tính.
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.util.Set;
import java.io.IOException;
public class FileAttributesDemo {
public static void main(String[] args) throws IOException {
Path path = Paths.get("example.txt");
if (!Files.exists(path)) {
System.out.println("Không tìm thấy tệp!");
return;
}
// Thuộc tính cơ bản
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
System.out.println("Tên: " + path.getFileName());
System.out.println("Đường dẫn: " + path.toAbsolutePath());
System.out.println("Kích thước: " + attrs.size() + " byte");
System.out.println("Tạo lúc: " + attrs.creationTime());
System.out.println("Sửa đổi lúc: " + attrs.lastModifiedTime());
System.out.println("Truy cập gần nhất: " + attrs.lastAccessTime());
System.out.println("Là thư mục? " + attrs.isDirectory());
System.out.println("Là tệp thông thường? " + attrs.isRegularFile());
// Kiểm tra quyền truy cập
System.out.println("Có thể đọc: " + Files.isReadable(path));
System.out.println("Có thể ghi: " + Files.isWritable(path));
System.out.println("Có thể thực thi: " + Files.isExecutable(path));
// Thử thay đổi thời gian sửa đổi
FileTime now = FileTime.fromMillis(System.currentTimeMillis());
Files.setLastModifiedTime(path, now);
System.out.println("Thời gian sửa đổi gần nhất đã được cập nhật!");
// Thử đặt tệp ẩn (nếu hỗ trợ)
try {
Files.setAttribute(path, "dos:hidden", true);
System.out.println("Tệp đã được đặt ẩn (nếu HĐH hỗ trợ).");
} catch (UnsupportedOperationException e) {
System.out.println("Tệp ẩn không được hỗ trợ trên HĐH này.");
}
// Thử in quyền POSIX (nếu hỗ trợ)
try {
PosixFileAttributes posixAttrs = Files.readAttributes(path, PosixFileAttributes.class);
System.out.println("Chủ sở hữu: " + posixAttrs.owner().getName());
System.out.println("Quyền: " + PosixFilePermissions.toString(posixAttrs.permissions()));
} catch (UnsupportedOperationException e) {
System.out.println("Thuộc tính POSIX không được hỗ trợ trên HĐH này.");
}
}
}
6. Những lưu ý hữu ích
Khác biệt đa nền tảng và mẹo
- Không phải mọi thuộc tính đều khả dụng trên mọi HĐH! Trên Windows không có quyền POSIX, còn trên Linux không có thuộc tính DOS.
- Luôn sử dụng try-catch! Các phương thức có thể ném UnsupportedOperationException hoặc IOException.
- Quyền truy cập không chỉ là “rwx”! Trên Windows, mô hình quyền khác; “chỉ đọc” có thể được đặt bởi chính sách bảo mật của HĐH.
- Khái niệm tệp ẩn là tương đối. Trên Unix, tệp ẩn nếu tên bắt đầu bằng dấu chấm (.hidden); trên Windows — nếu đặt thuộc tính dos:hidden.
Bảng: thuộc tính nào khả dụng ở đâu
| Thuộc tính | Windows (dos:*) | Linux/macOS (posix:*) |
|---|---|---|
| Thời gian tạo | + | + |
| Thời gian sửa đổi gần nhất | + | + |
| Thời gian truy cập gần nhất | + | + |
| Tệp ẩn | + | Chỉ tên bắt đầu bằng dấu chấm |
| Chỉ đọc | + | + |
| Quyền (rwx) | - | + |
| Chủ sở hữu, nhóm | - | + |
| Lưu trữ, hệ thống | + | - |
7. Những lỗi thường gặp khi làm việc với thuộc tính tệp
Lỗi số 1: Cố đọc hoặc thay đổi thuộc tính POSIX trên Windows. Trên Windows bạn sẽ nhận UnsupportedOperationException. Luôn xử lý ngoại lệ này nếu bạn viết mã đa nền tảng.
Lỗi số 2: Thay đổi thời gian sửa đổi của tệp đang được tiến trình khác mở. Ở một số hệ thống, tệp có thể bị khóa và thao tác sẽ thất bại.
Lỗi số 3: Kỳ vọng rằng thao tác “ẩn tệp” hoạt động giống nhau trên mọi HĐH. Trên Unix, tệp ẩn khi tên bắt đầu bằng dấu chấm (.gitignore), còn trên Windows — khi đặt thuộc tính dos:hidden. Đừng nhầm lẫn hai cách tiếp cận này.
Lỗi số 4: Bỏ qua việc kiểm tra sự tồn tại của tệp trước khi thao tác. Nếu tệp không tồn tại, bạn sẽ nhận NoSuchFileException khi cố lấy hoặc thay đổi thuộc tính.
Lỗi số 5: Không kiểm tra quyền truy cập. Nếu người dùng không có quyền thay đổi thuộc tính, thao tác sẽ thất bại. Trước khi thay đổi, hãy kiểm tra Files.isWritable(path).
GO TO FULL VERSION