1. Giới thiệu
Làm việc trực tiếp với luồng (StreamReader, StreamWriter, FileStream) rất hữu ích, đặc biệt khi cần kiểm soát quá trình đọc/ghi ở mức thấp: ví dụ, ghi theo khối nhỏ từng phần hoặc xử lý file lớn thành nhiều phần.
Nhưng trong thực tế thường chỉ cần biết: "file này có tồn tại không?", "copy file từ chỗ này sang chỗ kia", "xóa file", "lấy danh sách tất cả file .txt trong thư mục", v.v. Để xử lý những việc như vậy Microsoft tạo ra hai công cụ tổng quát: các lớp tĩnh File và Directory. Tĩnh có nghĩa là không cần tạo instance, gọi trực tiếp phương thức trên tên lớp.
Tương tự đời thường
Nếu luồng là bạn với cây bút chì đang viết từng chữ lên giấy, thì File và Directory giống như cái bàn có ngăn kéo: bạn có thể "mở ngay" một ngăn (Directory), lấy tờ giấy ra (File.ReadAllText), vứt tờ giấy đi (File.Delete) hoặc kéo cả ngăn đi chỗ khác (Directory.Move). Việc đơn giản thì phương thức đơn giản.
2. Lớp File: nó là gì và để làm gì
Lớp File có một bộ phương thức tĩnh rất tiện cho các thao tác phổ biến với file.
Các phương thức được dùng nhiều nhất
| Phương thức | Mô tả |
|---|---|
|
Kiểm tra xem file có tồn tại theo đường dẫn không |
|
Đọc toàn bộ file dưới dạng text |
|
Đọc tất cả các dòng của file vào mảng |
|
Ghi đè file, ghi text |
|
Thêm text vào cuối file |
|
Copy file |
|
Xóa file |
|
Di chuyển hoặc đổi tên file |
|
Mở stream cho các thao tác phức tạp |
Ví dụ nhanh: kiểm tra file và đọc nó
string filePath = "data.txt";
if (File.Exists(filePath))
{
string content = File.ReadAllText(filePath);
Console.WriteLine("Nội dung file:");
Console.WriteLine(content);
}
else
{
Console.WriteLine("Không tìm thấy file!");
}
Thấy chưa? Không cần quản lý stream thủ công cho trường hợp đơn giản!
3. Lớp Directory: quản lý thư mục không đau đớn
Nếu File là về file đơn lẻ, thì Directory là về thư mục (directory).
Nhiệm vụ chính
| Phương thức | Mô tả |
|---|---|
|
Kiểm tra xem thư mục tồn tại không |
|
Tạo thư mục (hoặc cả đường dẫn với các thư mục con) |
|
Xóa thư mục (có thể kèm subdirectories) |
|
Lấy danh sách file trong thư mục |
|
Lấy danh sách thư mục con |
|
Di chuyển hoặc đổi tên thư mục |
|
Lấy current working directory của ứng dụng |
Ví dụ: tạo thư mục và lưu file vào đó
string dirPath = "Results";
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
Console.WriteLine("Thư mục 'Results' đã được tạo.");
}
string filePath = Path.Combine(dirPath, "summary.txt");
File.WriteAllText(filePath, "Dữ liệu tổng kết: ...");
Console.WriteLine($"File {filePath} đã được ghi.");
4. Các kịch bản điển hình dùng File và Directory
Các phương thức cơ bản có vẻ chán nếu không thấy chúng trong thực tế! Hãy xem cách dùng các lớp này để giải quyết bài toán thực tế và, tiện thể, phát triển ứng dụng ví dụ của chúng ta (hãy tưởng tượng ta làm hệ thống todo-list đơn giản, lưu kết quả trong file).
Lưu dữ liệu vào file (thay thế file cũ)
// Lưu danh sách công việc vào file
string[] todos = { "Mua bánh mì", "Gọi bác sĩ", "Làm bài tập về nhà C#" };
string filePath = "todo.txt";
File.WriteAllLines(filePath, todos);
Console.WriteLine("Danh sách công việc đã được lưu.");
Tải dữ liệu từ file
// Tải công việc nếu file tồn tại
if (File.Exists(filePath))
{
string[] loadedTodos = File.ReadAllLines(filePath);
Console.WriteLine("Danh sách công việc của bạn:");
foreach (var task in loadedTodos)
{
Console.WriteLine("- " + task);
}
}
else
{
Console.WriteLine("Bạn chưa có danh sách công việc.");
}
Thêm công việc mới (không ghi đè file)
string newTask = "Dắt chó đi dạo";
File.AppendAllText(filePath, newTask + Environment.NewLine);
Console.WriteLine("Đã thêm công việc!");
Copy và backup file
string backupPath = "todo_backup.txt";
File.Copy(filePath, backupPath, overwrite: true);
Console.WriteLine("Đã tạo bản sao lưu danh sách công việc.");
Di chuyển (hoặc đổi tên) file
string archivePath = "todo_archive.txt";
File.Move(filePath, archivePath);
Console.WriteLine("Danh sách công việc đã được lưu trữ (đổi tên).");
Xóa file
if (File.Exists(archivePath))
{
File.Delete(archivePath);
Console.WriteLine("Đã xóa bản lưu — giải phóng chỗ!");
}
5. Làm việc với thư mục: ví dụ
Tạo cây thư mục
string path = Path.Combine("Reports", "2024", "June");
Directory.CreateDirectory(path);
Console.WriteLine($"Thư mục {path} đã được tạo (bao gồm các thư mục trung gian).");
Lấy danh sách file và thư mục
string dirPath = "Reports";
if (Directory.Exists(dirPath))
{
string[] files = Directory.GetFiles(dirPath);
Console.WriteLine("Các file trong thư mục:");
foreach (var file in files)
{
Console.WriteLine(file);
}
string[] subDirs = Directory.GetDirectories(dirPath);
Console.WriteLine("Thư mục con:");
foreach (var dir in subDirs)
{
Console.WriteLine(dir);
}
}
Lọc file theo mẫu (chỉ txt)
string[] txtFiles = Directory.GetFiles(dirPath, "*.txt");
Console.WriteLine("Chỉ các file .txt:");
foreach (var file in txtFiles)
{
Console.WriteLine(file);
}
Duyệt đệ quy (file trong tất cả thư mục con)
string[] allFiles = Directory.GetFiles(dirPath, "*.*", SearchOption.AllDirectories);
Console.WriteLine("Các file trong tất cả thư mục con:");
foreach (var file in allFiles)
{
Console.WriteLine(file);
}
Di chuyển và xóa thư mục
string from = "OldReports";
string to = "Archive/OldReports";
if (Directory.Exists(from))
{
Directory.Move(from, to);
Console.WriteLine($"Thư mục {from} đã được di chuyển tới {to}");
}
if (Directory.Exists(to))
{
Directory.Delete(to, recursive: true); // true: xóa toàn bộ bên trong
Console.WriteLine($"Thư mục {to} đã bị xóa (kèm nội dung).");
}
6. Các điểm hay hữu ích
Tích hợp với đường dẫn: lớp Path
Khi làm việc với file và thư mục thường phải ghép đường dẫn đầy đủ, nối tên thư mục và file, tách extension, kiểm tra ký tự hợp lệ. Dùng lớp trợ giúp Path.
Ví dụ
string folder = "Results";
string filename = "week1.txt";
string fullPath = Path.Combine(folder, filename); // ghép an toàn!
Console.WriteLine(fullPath); // "Results/week1.txt" (hoặc "\" trên Windows)
- Lấy phần mở rộng của file: Path.GetExtension(fullPath)
- Lấy tên file không kèm đường dẫn: Path.GetFileName(fullPath)
Dùng Path.Combine thay vì nối chuỗi — an toàn hơn cho ứng dụng đa nền tảng.
Phương thức "mọi thứ cùng lúc" vs phương thức luồng
Nhiều phương thức của File và Directory (ví dụ File.ReadAllText, File.WriteAllText, Directory.GetFiles) làm xong công việc "nguyên cái": đọc/ghi/lấy danh sách file trong một lần. Rất tiện, nhưng không phù hợp cho file hoặc thư mục rất lớn, nơi có thể hết bộ nhớ. Nếu làm việc với hàng GB — chuyển sang các lớp luồng (StreamReader, StreamWriter, FileStream, v.v.) hoặc xử lý theo phần.
Khi dùng File/Directory, khi dùng classes luồng
| Tình huống | Nên dùng |
|---|---|
| Cần kiểm tra file/thư mục có tồn tại | |
| Đọc/ghi toàn bộ file nhỏ | |
| Thêm text vào cuối file | |
| Lấy danh sách file trong thư mục | |
| Copy, xóa, di chuyển file | |
| Copy/xóa cả thư mục | Directory.Delete/Move/Copy (Copy — cần thư viện bên thứ 3) |
| Xử lý file RẤT lớn theo phần | Các lớp luồng (StreamReader, FileStream) |
Ý nghĩa thực tế và ứng dụng
- Tải/luu cấu hình nhanh, settings, file JSON/XML.
- Hệ thống logging (ghi log ra đĩa).
- Tiện ích sao lưu đơn giản (backup) và di chuyển dữ liệu.
- Quét thư mục chứa multimedia, ảnh, tài liệu.
- Kịch bản người dùng: tải template, export/import, tạo báo cáo, v.v.
Các bài tập phỏng vấn thực tế cũng thường yêu cầu dùng chính các lớp này: "Cài đặt hàm tính tổng kích thước tất cả file .txt trong thư mục", "Tạo bản sao lưu file vào thư mục riêng", v.v.
Sơ đồ nhanh: khi dùng phương thức nào
graph TD
A[Bạn muốn làm gì?]
A -->|Kiểm tra tồn tại| B[File.Exists hoặc Directory.Exists]
A -->|Đọc/ghi file nguyên cái| C[File.ReadAllText/WriteAllText]
A -->|Thêm dữ liệu vào file| D[File.AppendAllText]
A -->|Làm việc với thư mục| E[Directory.CreateDirectory, GetFiles, GetDirectories]
A -->|Copy/xóa/di chuyển file| F[File.Copy/Delete/Move]
A -->|Copy/xóa thư mục nguyên cái| G[Directory.Delete/Move]
7. Đặc điểm và lỗi hay gặp
Kiểm tra tồn tại và "race condition". Ngay cả khi kiểm tra file/thư mục tồn tại, giữa lần kiểm tra và khi thực hiện thao tác có thể có tiến trình khác thay đổi nó. Vì vậy luôn dùng try-catch ngay cả khi đã kiểm tra tồn tại!
Quyền truy cập. Nếu ứng dụng không có quyền đọc/ghi/xóa, phương thức sẽ ném UnauthorizedAccessException.
Đường dẫn quá dài. Độ dài tối đa của đường dẫn (thường là 260 ký tự trên Windows cũ; trong .NET 9 giới hạn mềm hơn, nhưng vẫn cẩn thận).
Bắt lỗi. Các phương thức như File.ReadAllText hoặc Directory.GetFiles không khoan nhượng: nếu file/thư mục không tồn tại — sẽ throw exception ngay. Bọc bằng try-catch hoặc kiểm tra tồn tại trước.
GO TO FULL VERSION