Trong quá trình lập trình, chắc hẳn ai trong chúng ta cũng từng cần đến việc lưu dữ liệu ra file: từ những dòng log để theo dõi chương trình, đến việc xuất báo cáo, lưu danh sách người dùng hay ghi lại kết quả xử lý. Đây là một thao tác tưởng chừng nhỏ, nhưng lại cực kỳ quan trọng để phần mềm vận hành mượt mà và tiện dụng.
Python mang đến cho lập trình viên một bộ công cụ mạnh mẽ và dễ dùng để làm việc với file. Chỉ với vài dòng lệnh, mình có thể tạo file mới, ghi dữ liệu văn bản hoặc nhị phân, thậm chí làm việc với định dạng phức tạp như CSV hay JSON. Không những vậy, Python còn hỗ trợ cơ chế quản lý tài nguyên an toàn, giúp hạn chế lỗi và đảm bảo dữ liệu được lưu trữ ổn định.
Trong bài viết này, mình sẽ cùng bạn đi qua toàn bộ kiến thức quan trọng về ghi file trong Python. Từ những thao tác cơ bản như open()
, write()
, đến những kỹ thuật nâng cao hơn như ghi theo chunks, xử lý encoding, hay sử dụng thư viện chuẩn để ghi dữ liệu có cấu trúc. Các ví dụ sẽ được trình bày chi tiết, giải thích rõ ràng, để bạn vừa có thể học lý thuyết, vừa thực hành ngay vào dự án thực tế.
1. Tổng quan về thao tác ghi file trong Python
Trong Python, thao tác cơ bản với file bao gồm: mở file (open) → ghi (write) → đóng (close). Hàm open()
trả về một object file, trên đó bạn gọi write()
hoặc writelines()
để ghi dữ liệu.
Các chế độ mở file quan trọng:
"w"
— write: tạo mới file hoặc xóa nội dung cũ rồi ghi mới."a"
— append: mở file để thêm vào cuối; nếu file chưa tồn tại thì tạo mới."x"
— exclusive creation: tạo file mới; nếu file đã tồn tại → lỗi.- Chế độ nhị phân:
"wb"
,"ab"
,"xb"
dùng để ghi dữ liệu bytes.
Ngoài ra còn có r+
, w+
… cho cả đọc và ghi cùng lúc. Khác biệt giữa text mode và binary mode là: text mode thao tác chuỗi (str
) với encoding, binary mode thao tác bytes
không chịu ảnh hưởng encoding.
2. Mở file để ghi bằng hàm open()
Cú pháp cơ bản:
file_obj = open(filename, mode, encoding=None)
Ví dụ đơn giản:
# Open a file for writing text (overwrite if exists)
file_name = "example.txt"
file_obj = open(file_name, "w", encoding="utf-8")
file_obj.write("Hello, world!\n")
file_obj.close()
Giải thích:
encoding="utf-8"
rất quan trọng khi làm việc với tiếng Việt để tránh lỗi mã hoá (UnicodeEncodeError).- Nếu quên
close()
, dữ liệu có thể không được flush vào ổ đĩa ngay lập tức — vì vậy dùngwith open()
(section 4) là cách an toàn hơn.
3. Ghi dữ liệu vào file với write()
và writelines()
write()
nhận một chuỗi và trả về số ký tự đã ghi:
# Using write()
filename = "names.txt"
with open(filename, "w", encoding="utf-8") as f:
# Write single lines using write()
f.write("Alice\n")
f.write("Bob\n")
writelines()
ghi các chuỗi trong một iterable:
# Using writelines()
lines = ["Charlie\n", "Diana\n", "Eve\n"]
with open("names2.txt", "w", encoding="utf-8") as f:
f.writelines(lines) # no automatic newline added
Lưu ý:
writelines()
không tự thêm ký tự xuống dòng, nên mỗi phần tử trong danh sách cần chứa\n
nếu muốn xuống dòng.write()
linh hoạt hơn khi bạn cần nối nhiều phần hoặc format từng dòng bằngf-string
.
Giải thích cụ thể: nếu bạn muốn ghi danh sách dữ liệu dạng văn bản, bạn có thể duyệt list và dùng write()
để thêm newline tự động (hoặc dùng join()
để ghép chuỗi trước khi ghi).
4. Ghi file với with open()
— Quản lý tài nguyên an toàn
Dùng context manager giúp tự động đóng file ngay cả khi có exception:
# Recommended pattern: with open()
data = ["Line 1", "Line 2", "Line 3"]
with open("output.txt", "w", encoding="utf-8") as fh:
for item in data:
fh.write(f"{item}\n")
# file is automatically closed after this block
Tại sao ưu tiên with open()
:
- Tự động
close()
khi thoát block, tránh leak file descriptor. - Ít rủi ro hơn nếu chương trình gặp lỗi giữa chừng.
- Mã ngắn gọn, dễ đọc.
5. Ghi dữ liệu nhị phân (binary files)
Khi thao tác với ảnh, âm thanh hoặc file nén, bạn cần viết bytes
:
# Writing binary data
binary_content = b'\x00\x01\x02\x03\x04' # example bytes
with open("data.bin", "wb") as bf:
bf.write(binary_content)
Ví dụ thực tế: sao chép file nhị phân (ảnh):
# Copy a binary file
with open("source.jpg", "rb") as src, open("dest.jpg", "wb") as dst:
while True:
chunk = src.read(4096) # read in chunks to avoid using too much memory
if not chunk:
break
dst.write(chunk)
Lưu ý:
- Đọc/ghi theo
chunk
(mảng byte) giúp xử lý file lớn mà không chiếm nhiều RAM. - Chế độ
"rb"
và"wb"
bắt buộc khi làm việc vớibytes
.
6. Các kỹ thuật nâng cao khi ghi file
Format khi ghi: dùng f-string
hoặc .format()
để tạo chuỗi có cấu trúc:
name = "Alice"
score = 95.5
with open("score.txt", "a", encoding="utf-8") as f:
f.write(f"{name}, {score:.1f}\n")
Ghi log với timestamp:
import datetime
with open("app.log", "a", encoding="utf-8") as logf:
timestamp = datetime.datetime.now().isoformat()
logf.write(f"{timestamp} - Application started\n")
Buffering và flush:
file.flush()
đẩy nội dung buffer xuống ổ đĩa ngay lập tức.open(..., buffering=1)
cho line-buffered,buffering=0
cho binary unbuffered (Python may restrict).print(..., file=f, flush=True)
có thể dùng để ghi ngay.
Xử lý ngoại lệ khi ghi file:
try:
with open("safe.txt", "w", encoding="utf-8") as f:
f.write("Important data\n")
except (IOError, OSError) as e:
# handle disk full, permission error, etc.
print("Failed to write file:", e)
Luôn bắt IOError
/ OSError
để xử lý tình huống như đầy ổ đĩa hoặc không có quyền ghi.
7. Thư viện hỗ trợ ghi dữ liệu có cấu trúc
CSV (csv
):
import csv
rows = [
["name", "age"],
["Alice", 30],
["Bob", 25]
]
with open("people.csv", "w", newline="", encoding="utf-8") as csvfile:
writer = csv.writer(csvfile)
writer.writerows(rows)
Giải thích: newline=""
để tránh tạo dòng trống trên Windows.
JSON (json
):
import json
data = {"title": "Example", "values": [1, 2, 3]}
with open("data.json", "w", encoding="utf-8") as jf:
json.dump(data, jf, ensure_ascii=False, indent=2)
ensure_ascii=False
giữ nguyên ký tự Unicode (tiếng Việt), indent=2
đẹp khi mở bằng editor.
Pickle (pickle
):
import pickle
obj = {"a": 1, "b": [1,2,3]}
with open("obj.pkl", "wb") as pf:
pickle.dump(obj, pf)
Lưu ý: không dùng pickle với dữ liệu không tin cậy vì rủi ro thực thi mã độc khi unpickle.
8. Lưu ý khi ghi file trong Python (Best Practices)
Trong thực tế, việc ghi file không chỉ dừng lại ở việc open()
và write()
. Để code an toàn, dễ bảo trì và chạy ổn định trong môi trường thực tế (sản xuất, server), bạn cần tuân theo một số thực tiễn tốt dưới đây:
8.1. Luôn dùng with open()
trừ khi có lý do đặc biệt
Sử dụng with open()
đảm bảo file được đóng tự động ngay cả khi có lỗi xảy ra. Điều này tránh rò rỉ tài nguyên (file descriptor leak).
Ví dụ:
# Good practice
with open("data.txt", "w", encoding="utf-8") as f:
f.write("This will be closed automatically.")
Ngược lại, nếu dùng open()
mà quên close()
, bạn có thể gặp lỗi khi hệ thống giới hạn số lượng file mở.
8.2. Chọn chế độ mở file phù hợp
"w"
(write): xoá nội dung cũ, ghi mới. Dùng khi chắc chắn bạn muốn overwrite."a"
(append): ghi nối vào cuối file, dữ liệu cũ vẫn còn."x"
(exclusive): chỉ tạo file mới, sẽ báo lỗi nếu file đã tồn tại (tránh overwrite nhầm).
Ví dụ, khi lưu log, bạn nên dùng "a"
thay vì "w"
để không mất log cũ.
8.3. Đặt encoding rõ ràng (UTF-8)
Khi làm việc với văn bản có dấu (như tiếng Việt), luôn chỉ rõ encoding="utf-8"
để tránh lỗi UnicodeEncodeError
.
with open("students.txt", "w", encoding="utf-8") as f:
f.write("OpenDev\n")
Nếu bỏ qua encoding, Python có thể dùng encoding mặc định của hệ điều hành, dẫn đến lỗi khi chạy trên máy khác.
8.4. Ghi theo chunks khi thao tác file lớn
Khi làm việc với file nhị phân (ảnh, video, dữ liệu log lớn), không nên đọc/ghi toàn bộ file một lần vì dễ gây Out of Memory (OOM). Thay vào đó, đọc/ghi từng khối (chunk) nhỏ:
with open("bigfile.dat", "rb") as src, open("copy.dat", "wb") as dst:
while chunk := src.read(8192): # 8 KB per chunk
dst.write(chunk)
Cách này giúp tiết kiệm RAM và vẫn đảm bảo tốc độ hợp lý.
8.5. Bắt ngoại lệ IO để chương trình không crash
Việc ghi file có thể thất bại do nhiều nguyên nhân: ổ đĩa đầy, file đang bị lock, không có quyền ghi… Vì vậy, luôn nên bao bọc trong try-except
:
try:
with open("important.txt", "w", encoding="utf-8") as f:
f.write("Critical data")
except (OSError, IOError) as e:
print("Error writing file:", e)
Như vậy, thay vì chương trình dừng đột ngột, bạn có thể log lỗi hoặc đưa ra thông báo cho người dùng.
8.6. Kiểm tra quyền ghi trước khi thao tác
Trong một số ứng dụng quan trọng, bạn nên kiểm tra quyền ghi trước để tránh lỗi runtime. Có thể dùng module os
để kiểm tra:
import os
filename = "output.txt"
if os.access(".", os.W_OK): # check write permission in current directory
with open(filename, "w") as f:
f.write("OK to write")
else:
print("No write permission in this directory!")
Điều này đặc biệt quan trọng khi chương trình chạy trong môi trường nhiều người dùng (multi-user system).
8.7. Không dùng pickle
cho dữ liệu không đáng tin cậy
pickle
cho phép ghi/đọc object Python, nhưng nó có thể thực thi mã độc khi unpickle dữ liệu từ nguồn lạ. Vì vậy:
- Chỉ dùng pickle khi dữ liệu do chính chương trình bạn sinh ra.
- Với dữ liệu chia sẻ giữa nhiều hệ thống, hãy ưu tiên JSON hoặc CSV.
8.8. Dùng module logging
thay vì tự ghi log
Khi ứng dụng phức tạp, bạn nên dùng module logging
thay vì thủ công open()
+ write()
. logging
hỗ trợ:
- Ghi log theo cấp độ (
DEBUG
,INFO
,WARNING
,ERROR
). - Tự động xoay vòng file log (log rotation).
- Định dạng log với timestamp.
Ví dụ:
import logging
logging.basicConfig(filename="app.log", level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s")
logging.info("Application started")
logging.warning("Low disk space")
Cách này giúp quản lý log chuyên nghiệp hơn nhiều so với việc tự write()
ra file.
9. Kết luận
Ghi file là kỹ năng cơ bản nhưng có nhiều chi tiết cần lưu ý: chọn chế độ mở file đúng, quản lý tài nguyên bằng with open()
, xử lý encoding, và dùng các thư viện chuẩn (csv
, json
, pickle
) khi cần. Khi thao tác file lớn hoặc file nhị phân, cần đọc/ghi theo chunk để tối ưu bộ nhớ. Trong thực tế, việc thiết kế luồng ghi file an toàn và có logging tốt giúp ứng dụng dễ gỡ lỗi và vận hành ổn định.
10. Tài liệu tham khảo
[1] M. Lutz, Learning Python, 5th ed. Sebastopol, CA: O’Reilly Media, 2013.
[2] A. Sweigart, Automate the Boring Stuff with Python, 2nd ed. San Francisco, CA: No Starch Press, 2019.
[3] Python Software Foundation, Python 3.13 Documentation. [Online]. Available: https://docs.python.org/3/
[4] G. Van Rossum and F. L. Drake, Python 3 Reference Manual. Scotts Valley, CA: CreateSpace, 2009.
[5] D. Beazley, Python Essential Reference, 4th ed. Boston, MA: Addison-Wesley, 2009.