1. Tạo tệp
Việc tạo tệp bằng chương trình diễn ra thường xuyên: cho log, dữ liệu tạm, xuất báo cáo, nhập dữ liệu, lưu cấu hình và nhiều mục đích khác. Trong Java, như bạn có lẽ đã đoán, tốt nhất nên dùng API hiện đại — java.nio.file.
Công cụ chính: Files.createFile(Path)
Phương thức này tạo một tệp mới tại đường dẫn chỉ định. Nếu tệp đã tồn tại, một ngoại lệ sẽ được ném ra.
Ví dụ: tạo tệp văn bản trong thư mục hiện tại
import java.nio.file.*;
public class CreateFileExample {
public static void main(String[] args) {
Path path = Path.of("hello.txt");
try {
Files.createFile(path);
System.out.println("Tệp đã được tạo: " + path.toAbsolutePath());
} catch (FileAlreadyExistsException e) {
System.out.println("Tệp đã tồn tại: " + path);
} catch (Exception e) {
System.out.println("Lỗi khi tạo tệp: " + e.getMessage());
}
}
}
Lưu ý:
Files.createFile ném ra FileAlreadyExistsException nếu tệp đã có. Vì vậy thường trước khi tạo tệp người ta kiểm tra sự tồn tại của nó.
Kiểm tra sự tồn tại của tệp
Path path = Path.of("hello.txt");
if (!Files.exists(path)) {
Files.createFile(path);
}
Mẹo:
Kiểm tra sự tồn tại của tệp không phải là biện pháp chống race condition giữa các luồng, nhưng với phần lớn kịch bản người dùng — vẫn là cách làm ổn.
Tóm tắt: điều gì xảy ra khi tạo tệp?
- Nếu tệp chưa tồn tại và đường dẫn hợp lệ — một tệp trống mới sẽ được tạo.
- Nếu tệp đã có — một ngoại lệ sẽ được ném.
- Nếu đường dẫn không hợp lệ, thiếu quyền hoặc thư mục không tồn tại — sẽ ném các ngoại lệ khác (IOException, NoSuchFileException, v.v.).
2. Tạo thư mục
Sự khác nhau giữa Files.createDirectory và Files.createDirectories
- Files.createDirectory(Path) — chỉ tạo một thư mục. Nếu không có thư mục cha — sẽ báo lỗi.
- Files.createDirectories(Path) — tạo toàn bộ chuỗi thư mục còn thiếu (như một pháp sư xây cầu thang ngay dưới chân bạn).
Ví dụ: tạo một thư mục
Path dir = Path.of("data");
try {
Files.createDirectory(dir);
System.out.println("Thư mục đã được tạo: " + dir.toAbsolutePath());
} catch (FileAlreadyExistsException e) {
System.out.println("Thư mục đã tồn tại: " + dir);
} catch (Exception e) {
System.out.println("Lỗi khi tạo thư mục: " + e.getMessage());
}
Ví dụ: tạo cấu trúc thư mục lồng nhau
Path nested = Path.of("data/reports/2024");
try {
Files.createDirectories(nested);
System.out.println("Cấu trúc thư mục đã được tạo: " + nested.toAbsolutePath());
} catch (Exception e) {
System.out.println("Lỗi khi tạo cấu trúc: " + e.getMessage());
}
Lưu ý: nếu một số thư mục đã tồn tại, createDirectories không hề bận tâm — nó chỉ tạo những thư mục còn thiếu. Nếu dùng createDirectory cho thư mục lồng mà thư mục cha chưa có — sẽ bị lỗi.
Bảng: so sánh các phương thức tạo thư mục
| Phương thức | Chỉ tạo một thư mục | Tạo thư mục lồng nhau | Không thất bại nếu một phần đã tồn tại |
|---|---|---|---|
|
✔ | ✗ | ✗ |
|
✔ | ✔ | ✔ |
3. Xóa tệp
Xóa tệp gần như giống vứt rác: điều quan trọng — đừng lỡ tay vứt thứ cần thiết! Trong Java có hai phương thức chính cho việc này:
- Files.delete(Path) — xóa tệp hoặc thư mục rỗng. Nếu không có tệp — sẽ ném ngoại lệ.
- Files.deleteIfExists(Path) — xóa tệp, nhưng nếu tệp không tồn tại — chỉ im lặng, không làm gì.
Ví dụ: xóa tệp tạm
Path tempFile = Path.of("temp.txt");
try {
Files.delete(tempFile);
System.out.println("Tệp đã bị xóa: " + tempFile);
} catch (NoSuchFileException e) {
System.out.println("Không tìm thấy tệp: " + tempFile);
} catch (DirectoryNotEmptyException e) {
System.out.println("Thư mục không rỗng: " + tempFile);
} catch (Exception e) {
System.out.println("Lỗi khi xóa: " + e.getMessage());
}
Cách an toàn hơn
boolean deleted = Files.deleteIfExists(tempFile);
if (deleted) {
System.out.println("Tệp đã được xóa.");
} else {
System.out.println("Không tìm thấy tệp — không có gì để xóa.");
}
Quan trọng!
- Nếu tệp đang mở trong chương trình khác — có thể ném ngoại lệ (ví dụ trên Windows).
- Nếu cố xóa thư mục không rỗng — sẽ gặp lỗi DirectoryNotEmptyException.
4. Xóa thư mục
Trong Java, ta xóa thư mục tương tự như tệp. Chỉ có một điểm khác: các phương thức tiêu chuẩn chỉ xóa thư mục rỗng.
Ví dụ: xóa thư mục rỗng
Path emptyDir = Path.of("empty_folder");
try {
Files.delete(emptyDir);
System.out.println("Thư mục đã bị xóa: " + emptyDir);
} catch (DirectoryNotEmptyException e) {
System.out.println("Thư mục không rỗng: " + emptyDir);
} catch (NoSuchFileException e) {
System.out.println("Không tìm thấy thư mục: " + emptyDir);
} catch (Exception e) {
System.out.println("Lỗi khi xóa thư mục: " + e.getMessage());
}
Phải làm gì với thư mục không rỗng?
Để xóa thư mục không rỗng, bạn cần xóa đệ quy tất cả tệp và thư mục con bên trong. Đây là chủ đề cho một bài giảng riêng (và một cuộc phiêu lưu riêng), nhưng nếu nóng lòng, đây là đoạn mã — hãy đọc hiểu và thử làm theo:
import java.nio.file.*;
import java.io.IOException;
public class DeleteDirectoryRecursively {
public static void deleteRecursively(Path path) throws IOException {
if (Files.isDirectory(path)) {
try (var entries = Files.list(path)) {
for (Path entry : entries.toList()) {
deleteRecursively(entry);
}
}
}
Files.delete(path);
}
}
Chú ý:
Đoạn mã này sẽ xóa mọi thứ bên trong thư mục! Hãy sử dụng thận trọng.
5. Mẹo thực tiễn
Kiểm tra tồn tại trước khi xóa
if (Files.exists(path)) {
Files.delete(path);
} else {
System.out.println("Tệp/thư mục không tồn tại.");
}
Nhưng nếu bạn dùng deleteIfExists thì không nhất thiết phải làm vậy.
Xử lý ngoại lệ
Khi làm việc với tệp, chúng ta thường gặp những tình huống bất ngờ. Java ném ra nhiều loại ngoại lệ cho các tình huống này:
- NoSuchFileException — tệp hoặc thư mục không tìm thấy. Ví dụ, bạn cố mở thứ đã bị xóa.
- DirectoryNotEmptyException — bạn muốn xóa thư mục nhưng bên trong vẫn còn nội dung.
- IOException — cảnh báo chung: có điều gì đó không ổn. Nguyên nhân có thể khác nhau — thiếu quyền truy cập, tệp đang bị chương trình khác sử dụng, đường dẫn không hợp lệ.
Sơ đồ trực quan: các phương thức chính
+-------------------+ +--------------------+
| Files.createFile | ----> | Tệp mới |
+-------------------+ +--------------------+
+---------------------+ +--------------------+
| Files.createDirectory|----> | Thư mục mới |
+---------------------+ +--------------------+
+-------------------+ +--------------------+
| Files.delete | ----> | Tệp/thư mục đã xóa |
+-------------------+ +--------------------+
(nhưng chỉ khi thư mục rỗng!)
6. Lỗi thường gặp khi tạo và xóa tệp và thư mục
Lỗi #1: Cố tạo tệp/thư mục đã tồn tại. Các phương thức Files.createFile và Files.createDirectory ném ngoại lệ nếu đối tượng đã có. Cách xử lý — kiểm tra tồn tại trước hoặc bắt ngoại lệ.
Lỗi #2: Cố tạo thư mục lồng bằng createDirectory khi thư mục cha chưa có. Khi đó sẽ có lỗi NoSuchFileException. Hãy dùng createDirectories để tạo chuỗi thư mục.
Lỗi #3: Cố xóa thư mục không rỗng bằng Files.delete. Bạn sẽ gặp DirectoryNotEmptyException. Để xóa thư mục không rỗng cần đệ quy.
Lỗi #4: Thiếu quyền tạo/xóa trong thư mục chỉ định. Sẽ ném AccessDeniedException hoặc IOException. Hãy chạy chương trình với quyền phù hợp hoặc sử dụng thư mục có quyền.
Lỗi #5: Tệp đang bị tiến trình khác sử dụng. Trên Windows (và đôi khi trên các hệ điều hành khác) không thể xóa tệp nếu nó đang được mở bởi chương trình khác. Bạn sẽ gặp IOException. Hãy đóng mọi ứng dụng đang dùng tệp trước khi xóa.
Lỗi #6: Sử dụng đường dẫn tương đối mà không biết “bạn đang ở đâu”. Tệp được tạo không đúng nơi bạn kỳ vọng. Để chắc chắn, hãy dùng toAbsolutePath() và in đường dẫn ra màn hình.
GO TO FULL VERSION