1. Giới thiệu
Nếu các lớp static như File và Directory giống như một con dao Thụy Sĩ đa năng: luôn sẵn, giải quyết nhanh vấn đề nhưng không gắn với một đối tượng cụ thể, thì FileInfo và DirectoryInfo là công cụ cá nhân hoá: được tạo cho một tệp hoặc thư mục cụ thể, "biết" nhiều thứ về chúng và cho phép thao tác tiện hơn, linh hoạt hơn, đặc biệt khi làm nhiều thao tác trên cùng một đối tượng.
Các lớp thể hiện giữ chi tiết về một đối tượng cụ thể trong hệ thống file, và sau lần tải đầu tiên thì không nhất thiết phải truy vấn lại filesystem (trừ khi đối tượng bị cũ).
- FileInfo — để làm việc với một tệp cụ thể.
- DirectoryInfo — để làm việc với một thư mục cụ thể.
Chúng có các thuộc tính và phương thức cho phép lấy thông tin chi tiết (kích thước, ngày tạo, phần mở rộng, các attribute) và thực hiện các hành động trên tệp/thư mục: sao chép, xóa, di chuyển, v.v.
Cấu trúc của FileInfo và DirectoryInfo
Cả hai lớp đều kế thừa từ một lớp trừu tượng chung FileSystemInfo, nên có thể viết mã xử lý cả file và thư mục một cách tổng quát.
System.Object
|
System.MarshalByRefObject
|
System.IO.FileSystemInfo (lớp trừu tượng)
| |
FileInfo DirectoryInfo
Khi nào nên dùng các lớp thể hiện?
- Nếu cần nhiều thông tin về một tệp/thư mục (kích thước, ngày chỉnh sửa, phần mở rộng, attributes, v.v.) và những dữ liệu đó được dùng nhiều lần.
- Nếu bạn muốn duyệt qua tất cả các tệp/thư mục trong một thư mục và làm việc với mỗi đối tượng như một instance "sống".
- Để tối ưu hóa khi quan trọng không truy vấn filesystem quá nhiều lần (caching thông tin).
- Cho mã theo phong cách OOP hơn (backup, media library, file manager, v.v.).
Cách tạo instance của FileInfo hoặc DirectoryInfo
using System.IO;
// Tạo đối tượng FileInfo cho một tệp tồn tại (hoặc chưa tồn tại!):
var fileInfo = new FileInfo("notes.txt");
// Tạo đối tượng DirectoryInfo cho một thư mục:
var dirInfo = new DirectoryInfo(@"C:\Projects");
// Có thể dùng đường dẫn tương đối hoặc tuyệt đối!
Lưu ý quan trọng: tạo đối tượng FileInfo hoặc DirectoryInfo KHÔNG tạo tệp/thư mục trên filesystem! Nó chỉ là mô tả (liên kết).
2. Làm việc với FileInfo
Ta cùng xem các thuộc tính và phương thức chính của lớp này. Ghi chú nhanh:
| Thuộc tính/phương thức | Trả về gì? | Ví dụ sử dụng |
|---|---|---|
|
Tên tệp | |
|
Đường dẫn đầy đủ | |
|
Kích thước tệp tính bằng byte | |
|
Thư mục cha (DirectoryInfo) | |
|
Tệp có thực sự tồn tại không? | |
|
Phần mở rộng của tệp (.txt) | |
|
Ngày tạo | |
|
Ngày chỉnh sửa lần cuối | |
|
Chỉ đọc không? | |
| Phương thức | ||
|
Sao chép tệp | |
|
Xóa tệp | |
|
Di chuyển tệp | |
|
Mở stream để đọc | |
|
Mở stream để ghi | |
Ví dụ: Thông tin về tệp
Thêm module nhỏ để lấy thông tin chi tiết về tệp dùng FileInfo.
Console.WriteLine("Nhập tên tệp:");
string fileName = Console.ReadLine();
var file = new FileInfo(fileName);
if (file.Exists)
{
Console.WriteLine($"Tên tệp: {file.Name}");
Console.WriteLine($"Đường dẫn: {file.FullName}");
Console.WriteLine($"Kích thước: {file.Length} byte");
Console.WriteLine($"Phần mở rộng: {file.Extension}");
Console.WriteLine($"Ngày tạo: {file.CreationTime}");
Console.WriteLine($"Chỉnh sửa lần cuối: {file.LastWriteTime}");
// Thêm: hiển thị thư mục cha
Console.WriteLine($"Thư mục cha: {file.DirectoryName}");
}
else
{
Console.WriteLine("Không tìm thấy tệp.");
}
Lưu ý: chúng ta không đọc nội dung tệp, chỉ lấy meta-info thôi.
Thực hành: Sao chép và xóa tệp
// ... Trong phương thức chính, sau khi in thông tin tệp thành công:
Console.WriteLine("Nhập đường dẫn cho bản sao của tệp:");
string copyPath = Console.ReadLine();
try
{
file.CopyTo(copyPath);
Console.WriteLine($"Đã sao chép tệp thành công tới {copyPath}");
}
catch (IOException ex)
{
Console.WriteLine($"Không thể sao chép tệp: {ex.Message}");
}
// Bây giờ xóa bản sao
Console.WriteLine("Xóa bản sao tệp? (y/n):");
if (Console.ReadLine().Trim().ToLower() == "y")
{
var copyFile = new FileInfo(copyPath);
if (copyFile.Exists)
{
copyFile.Delete();
Console.WriteLine("Đã xóa bản sao.");
}
}
3. Làm việc với DirectoryInfo
Xem xem DirectoryInfo mang lại gì:
| Thuộc tính/phương thức | Trả về gì? | Ví dụ sử dụng |
|---|---|---|
|
Tên thư mục | |
|
Đường dẫn đầy đủ | |
|
Thư mục cha (DirectoryInfo) | |
|
Thư mục có tồn tại? | |
|
Ngày tạo | |
|
Ngày chỉnh sửa | |
| Phương thức | ||
|
Tạo thư mục | |
|
Xóa thư mục | |
|
Mảng các tệp (mảng FileInfo) | |
|
Mảng các thư mục con (mảng DirectoryInfo) | |
|
Duyệt các tệp (trả về IEnumerable<FileInfo>, chế độ lazy) | |
|
Di chuyển thư mục | |
Ví dụ: Duyệt tệp và thư mục
Console.WriteLine("Nhập đường dẫn tới thư mục:");
string path = Console.ReadLine();
var dir = new DirectoryInfo(path);
if (!dir.Exists)
{
Console.WriteLine("Không tìm thấy thư mục!");
return;
}
Console.WriteLine("\n--- Các tệp ---");
foreach (var file in dir.GetFiles())
{
Console.WriteLine($"{file.Name} ({file.Length} byte)");
}
Console.WriteLine("\n--- Thư mục con ---");
foreach (var subDir in dir.GetDirectories())
{
Console.WriteLine(subDir.Name);
}
4. Một vài lưu ý hữu ích
Phương thức static so với lớp thể hiện
Khi nào nên chọn cái nào? Nếu bạn làm một hành động "một lần" nhanh — ví dụ File.Exists(path) hoặc File.ReadAllText(path) — thì các phương thức static tỏ ra tiện và nhanh hơn do overhead nhỏ.
Còn nếu bạn cần nhiều thông tin về một tệp hoặc thư mục, thực hiện nhiều thao tác lặp lại trên đối tượng đó, hoặc đơn giản là viết theo phong cách OOP — thì dùng các instance FileInfo và DirectoryInfo sẽ phù hợp hơn.
Thú vị là cả hai cách ở dưới nắp máy đều gọi các system call tương tự. Nhưng các lớp thể hiện cache một số thuộc tính (kích thước, ngày, attributes), giảm số lần truy vấn filesystem — rất hữu ích khi duyệt số lượng lớn tệp.
Vài điều về ngày giờ
Các thuộc tính CreationTime, LastWriteTime, LastAccessTime trả về kiểu DateTime.
Console.WriteLine($"Tệp tạo: {file.CreationTime:yyyy-MM-dd HH:mm:ss}");
Console.WriteLine($"Chỉnh sửa lần cuối: {file.LastWriteTime:yyyy-MM-dd HH:mm:ss}");
Nếu tệp hoặc thư mục bị thay đổi trên đĩa sau khi bạn tạo instance FileInfo hoặc DirectoryInfo, thông tin cache có thể đã cũ. Để cập nhật, gọi file.Refresh().
Mẹo và chú ý thực tế
- Các lớp thể hiện tiện khi bạn xây wrapper quanh filesystem: backup, media library, indexer.
- Hoạt động tốt cùng với LINQ: lọc theo kích thước, ngày hay phần mở rộng rồi thực hiện thao tác trên các đối tượng được chọn.
- Với thao tác số lượng lớn ưu tiên dùng EnumerateFiles() và EnumerateDirectories() hơn GetFiles()/GetDirectories() — enumerating lazy tiết kiệm bộ nhớ và nhanh hơn khi bắt đầu xử lý.
So sánh giữa cách static và cách instance
| Phương thức static | Các lớp thể hiện | |
|---|---|---|
| Cú pháp | |
|
| Cache | Không | Có |
| Nhiều thông tin | Phải gọi nhiều phương thức | Đã có trong đối tượng |
| Phong cách OOP | Không | Có |
| Thao tác số lượng lớn | Không thuận tiện | Thuận tiện |
| Làm việc với stream | Có | Có |
Cập nhật thông tin và các đối tượng
Các đối tượng FileInfo/DirectoryInfo cache giá trị sau lần truy cập đầu tiên. Nếu đối tượng (tệp hoặc thư mục) bị thay đổi trên đĩa sau khi tạo instance, để cập nhật thông tin hãy gọi phương thức .Refresh().
var file = new FileInfo("notes.txt");
long oldSize = file.Length;
// Lúc này có thể ai đó (hoặc bạn) thay đổi tệp ngoài chương trình
file.Refresh();
long newSize = file.Length;
Không thường xuyên gặp, nhưng nếu chương trình của bạn giám sát filesystem — cơ chế này quan trọng.
5. Lỗi thường gặp khi làm việc với lớp thể hiện
Hiểu lầm: nếu tạo đối tượng new FileInfo("file.txt") thì tệp đã tồn tại. Thực tế không phải vậy — tệp chỉ xuất hiện sau khi ghi rõ ràng hoặc gọi Create().
Cố gắng lấy thuộc tính của tệp không tồn tại: một số thuộc tính sẽ trả giá trị mặc định (ví dụ kích thước sẽ là 0), nhưng cố mở stream để đọc sẽ ném ngoại lệ.
Với thư mục cũng tương tự: tạo DirectoryInfo không bảo đảm thư mục có trên đĩa trừ khi gọi Create() hoặc thư mục đó thực sự xuất hiện.
GO TO FULL VERSION