Câu 1Cái nào sau đây bạn dùng khi muốn xóa đệ quy cả folder?
shutil và tempfile — Thao tác file hàng loạt và file tạm
Học shutil và tempfile của Python từ căn bản. Thao tác file hàng loạt với shutil.copy / shutil.move / shutil.rmtree, cùng cách dùng file tạm an toàn qua tempfile.NamedTemporaryFile — đều có thực hành.
Bài này đi qua hai module: shutil, thao tác trên cả file và folder, và tempfile, xử lý file tạm dùng một lần. Bạn sẽ phủ thao tác file hàng loạt với shutil.copy / move / rmtree, cách an toàn dùng NamedTemporaryFile, và pattern atomic write kết hợp cả hai.
shutil — Thao tác file và folder trong một dòng
shutil viết tắt của shell utilities — đây là thư viện chuẩn cho phép bạn gọi các thao tác kiểu shell như cp / mv / rm -r từ Python trong một dòng. Module os có những thứ như os.rename, nhưng shutil thêm các thao tác cấp cao hơn như copy folder đệ quy và xóa cây.
| Hàm | Hành vi | Ghi chú |
|---|---|---|
| shutil.copy(src, dst) | Nhân bản file | Nếu dst là folder, nó vào trong với cùng tên |
| shutil.copy2(src, dst) | copy cộng metadata như thời gian sửa đổi | Tốt cho backup |
| shutil.copytree(src, dst) | Nhân bản đệ quy cả folder | dst **không được tồn tại** |
| shutil.move(src, dst) | Di chuyển hoặc đổi tên file hoặc folder | Tương đương rename khi src và dst chia sẻ cùng cha |
| shutil.rmtree(path) | Xóa đệ quy folder và nội dung | Không thể đảo ngược — kiểm tra kỹ mục tiêu trước khi chạy |
import shutil
import os
# 1) Copy file đến vị trí khác (backup điển hình)
os.makedirs("backups", exist_ok=True) # Đảm bảo folder đích tồn tại
shutil.copy("data/sales.csv", "backups/sales_2024.csv")
shutil.move("logs/temp.log", "logs/archive_2024.log")
shutil.rmtree("old_data")
rmtree không thể hoàn tác
shutil.rmtree(path) xóa vật lý mọi thứ dưới path. Python không đi qua thùng rác — nó biến mất ngay lập tức. Trong dự án thật, hãy in mục tiêu trước khi xóa, thêm guard như if path.startswith("/tmp"), và xây thói quen bảo vệ cả bạn và code.
tempfile — Tạo file dùng một lần an toàn
tempfile là thư viện chuẩn cho file tạm tự động dọn dẹp khi bạn xong với chúng. Bạn dùng nó để lưu kết quả trung gian, đệm dữ liệu lớn, giữ folder làm việc test — bất cứ thứ gì chỉ cần tồn tại trong khi tiến trình chạy.
Nếu bạn tự làm tên file như tmp_xxx.txt, bạn có nguy cơ đụng với tiến trình khác hoặc quên xóa chúng. tempfile thay vào đó tạo file trong folder tạm của OS dưới tên đảm bảo duy nhất, và xóa chúng tự động khi việc xong.
with, và tự động bị xóa khi bạn rời nó. Tên file được gán tại chỗ để tránh đụng — bạn không tự chọn nó.| Hàm / thuộc tính | Ý nghĩa | Ghi chú |
|---|---|---|
| tempfile.NamedTemporaryFile | File tạm bạn mở và đóng với `with` | delete=False giữ nó sau block |
| tempfile.mkdtemp() | Trả về đường dẫn folder tạm | Bạn tự xóa nó với shutil.rmtree |
| tempfile.gettempdir() | Trả về đường dẫn folder tạm OS | /tmp trên Linux, đường dẫn khác trên macOS |
| tf.name | Đường dẫn file thực (tên ngẫu nhiên) | Truy cập được trong block `with` |
| tf.write / tf.read | Cùng API như đối tượng file thường | Chọn 'w' / 'r' / 'w+' qua tham số mode |
import tempfile
import os
# Mở an toàn với `with`, rồi tự xóa
with tempfile.NamedTemporaryFile(mode="w+", suffix=".txt", delete=True) as tf:
tf.write("dữ liệu tổng hợp trung gian\n")
tf.seek(0)
print("Content:", tf.read())
print("Path:", tf.name)
# ← Block kết thúc đây và file tự bị xóa
Khi nào kết hợp delete=False với `with`
Khi bạn muốn viết file và đọc lại nó sau từ chỗ khác, truyền delete=False để file sống sót khi rời block with. Một khi xong với nó, hoặc tự xóa với os.remove(path) hoặc swap nó vào đích thực với shutil.move — đó là pattern atomic write phủ bên dưới.
File tạm tự xóa với `delete=True`
Nếu bạn ghi đè file config quan trọng hoặc file state trực tiếp với open("settings.json", "w"), crash tiến trình giữa chừng ghi có thể để lại file viết một nửa, sau đó fail parse ở lần đọc tiếp. Cách chuẩn để tránh điều này là pattern "ghi đầy đủ vào file tạm, rồi rename / move nó vào đường dẫn thực" — gọi là atomic write (atomic — kể cả bị gián đoạn, người quan sát chỉ có thể thấy "hoàn thành" hoặc "chưa bắt đầu", không bao giờ trạng thái giữa chừng).
import tempfile
import shutil
import json
final_path = "settings.json"
new_settings = {"theme": "dark", "lang": "en", "fontSize": 14}
# 1) Ghi đầy đủ vào file tạm
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".json") as tf:
json.dump(new_settings, tf)
temp_path = tf.name
# 2) Khi xong, move vào đường dẫn thực (khoảnh khắc đơn này là "swap")
shutil.move(temp_path, final_path)
# 3) Xác minh
with open(final_path) as f:
print(json.load(f))
# → {'theme': 'dark', 'lang': 'en', 'fontSize': 14}
Đối tượng file có vị trí đọc/ghi hiện tại (cursor), và gọi `tf.write(...)` di chuyển cursor ngay sau cái đã được ghi (= cuối). Gọi tf.read() từ đó trả về chuỗi rỗng vì không có gì sau cursor, nên nước đi chuẩn là reset cursor về đầu với `tf.seek(0)` trước khi đọc.
mode="w+" là Read-Write Mode
`mode="w+"` là mode cho phép bạn vừa ghi vừa đọc qua cùng file handle. Với chỉ "w" bạn chỉ ghi và read() không hoạt động; với chỉ "r" bạn chỉ đọc và write() không hoạt động. Cho bài tập viết và đọc lại ngay, "w+" là bắt buộc.
Kiểm tra kiến thức
Hãy trả lời từng câu hỏi một.
Câu 2Lý do điển hình để dùng tempfile.NamedTemporaryFile với delete=False là gì?
Câu 3Bản chất của atomic write là gì?