Hướng dẫn 8 cách sử dụng hàm open() trong Python

Hàm open()
của Python nên là lựa chọn đầu tiên của bạn khi bạn muốn đọc nội dung của một tệp. Hãy cung cấp tên tệp cho nó và bạn sẽ nhận lại một đối tượng linh hoạt, cho phép bạn đọc và ghi dữ liệu, cả ở định dạng văn bản thuần túy và định dạng nhị phân (binary).
Những ví dụ này sẽ cho thấy hàm này linh hoạt đến mức nào, với sự hỗ trợ cho các chế độ (modes) khác nhau, việc đệm (buffering), mã hóa (encoding), và nhiều hơn nữa.
Xem thêm: Hướng dẫn cách hiển thị thời gian trong trung tâm thông báo trên Windows 11
1. Mở một tệp và đọc nội dung của nó
Hàm open()
có cú pháp khá phức tạp, nhưng trong những trường hợp đơn giản nhất, bạn có thể dùng nó để mở một tệp văn bản như sau:
f = open(filename)
Mặc định, Python mở tệp này ở chế độ đọc (read mode), nghĩa là bạn chỉ có thể đọc từ nó. Điều này lý tưởng cho các tệp cấu hình, tệp dữ liệu tĩnh, v.v… Nó cũng làm cho trường hợp phổ biến này trở nên ngắn gọn và dễ nhớ.
Hàm open()
trả về một đối tượng tệp (file object) mà sau đó bạn có thể sử dụng để thực hiện các tác vụ khác nhau, bao gồm đọc toàn bộ nội dung của tệp:
f = open("/usr/share/dict/words")
text = f.read()
print(text)
Lưu ý rằng đoạn mã đơn giản này sẽ khiến Python báo lỗi (raise an exception) nếu tệp không tồn tại.
Một tệp được đảm bảo tồn tại là tập lệnh mà bạn đang chạy, mà Python cung cấp trong biến đặc biệt __file__
. Điều này giúp việc viết một tập lệnh in mã nguồn của chính nó, hay còn gọi là một quine, trở nên đơn giản:
f = open(__file__)
text = f.read()
print(text)
Nếu thực sự nghiêm ngặt, đây không hoàn toàn là một quine vì việc đọc tệp được coi là gian lận.
2. Sử dụng từ khóa with
để đóng tệp tự động
Khi Python mở một tệp, nó cấp phát các tài nguyên hệ thống cho tệp đó, sau đó sử dụng cho các thao tác trong tương lai như đọc và ghi. Nếu chương trình của bạn chạy đến cuối, Python sẽ dọn dẹp các tài nguyên này, giúp chúng có sẵn cho các quy trình khác có thể chạy trên hệ thống của bạn. Nhưng điều này không được đảm bảo, vì vậy bạn luôn luôn phải đảm bảo các tài nguyên được dọn dẹp chính xác. Cách đơn giản nhất để làm điều đó là gọi tường minh phương thức close()
trên tệp của bạn khi bạn biết mình đã hoàn thành công việc với nó:
f = open("/usr/share/dict/words")
text = f.read()
f.close()
Hãy cố gắng đóng tệp ngay khi có thể. Ví dụ, nếu bạn mở một tệp, đọc nội dung của nó, và sau đó xử lý nội dung đó, hãy cố gắng đóng tệp ngay khi bạn đã đọc nội dung vào một biến. Không cần phải giữ tệp mở trong khi bạn xử lý dữ liệu đã đọc.
Nhưng các vấn đề vẫn có thể xảy ra: điều gì sẽ xảy ra nếu lệnh gọi close()
không chạy đúng cách? Để giải quyết vấn đề này, bạn nên sử dụng từ khóa with
. Điều này tạo ra một trình quản lý ngữ cảnh (context manager) cho khối mã nó bao bọc, đảm bảo các tài nguyên tệp được giải phóng:
with open("/usr/share/dict/words") as f:
text = f.read()
3. Sao chép tệp bằng cách đọc và ghi
Nhiều thư viện Python cung cấp các cách để sao chép một tệp, vì vậy ví dụ này chỉ mang tính chất minh họa. Nó thể hiện cách sử dụng đối số thứ hai của open
, đó là chế độ (mode). Đối số này cho open
biết bạn định sử dụng tệp như thế nào. Bạn có thể sử dụng bất kỳ sự kết hợp hợp lệ nào của các ký tự này:
Chế độ mặc định là rt
—đọc một tệp văn bản—đó là lý do tại sao ví dụ đầu tiên trong bài viết này hoạt động như bạn mong đợi. Để sao chép tệp bạn đọc, bạn sẽ cần mở một tệp thứ hai bằng chế độ w
để ghi. Bạn cũng sẽ cần sử dụng chế độ b
cho cả hai tệp để đảm bảo các thao tác đọc và ghi tôn trọng dữ liệu nhị phân.
source = "./image.jpg"
target = "./a-copy-of-image.jpg"
with open(source, "rb") as src, open(target, "wb") as tgt:
buffer = src.read()
tgt.write(buffer)
Khối with
hoạt động trên cả hai tệp, vì vậy nó sẽ tự động đóng chúng khi hoàn thành.
Mặc dù hàm open
của Python cung cấp cho bạn quyền truy cập cấp thấp vào nội dung của một tệp, module os
lại cung cấp nhiều hàm cấp cao hơn để thao tác trên các tệp và hệ thống tệp.
4. Tạo một tệp văn bản mới
Bạn cũng có thể sử dụng đối số mode
để tạo một tệp mới, nhưng bảo vệ bất kỳ tệp cùng tên nào có thể đã tồn tại:
open(filename, "x")
Nếu một tệp cùng tên đã tồn tại, lệnh gọi open
này sẽ ném ra ngoại lệ FileExistsError
. Đây là một biện pháp phòng vệ tốt, giúp bạn không cần phải kiểm tra rõ ràng sự tồn tại của tệp:
# Cảnh báo: không nên làm điều này!
import os.path
filename = "example.txt"
if os.path.isfile(filename):
print("Xin lỗi, tệp đã tồn tại")
else:
with open(filename, "w") as f:
# ...
Bên cạnh việc phải viết ít mã hơn một chút, còn có một lý do tốt hơn để sử dụng chế độ "x"
: nó tránh điều kiện tranh chấp (race condition). Hãy xem xét ví dụ trên, có một câu lệnh kiểm tra xem tệp có tồn tại hay không (if os.path.isfile(filename)
) theo sau là một câu lệnh khác mở tệp để ghi (with open(filename, "w") as f
). Nếu một quy trình khác làm gì đó với tệp đó ở giữa hai câu lệnh này, thảm họa có thể xảy ra.
Mở tệp ở chế độ tạo mới ("x"
) có thể ngăn chặn thảm họa vì chỉ một câu lệnh chịu trách nhiệm kiểm tra tệp và mở nó. Hoặc nó thất bại, và tệp hiện có được bảo vệ, hoặc nó thành công, và không có quy trình nào khác có thể tạo một tệp cùng tên trong thời gian đó.
5. Ghi vào tệp Log bằng cách ghi tiếp vào cuối
Theo mặc định, một tệp mà bạn mở ở chế độ ghi ("w"
) sẽ bị cắt ngắn (truncated) trước, vì vậy nội dung của nó sẽ bị ghi đè. Để ghi tiếp vào cuối tệp, bạn có thể sử dụng chế độ ghi tiếp (append mode
):
log = open("file.log", "a")
Lại nói, việc ghi log trong Python được xử lý tốt hơn bằng module logging
, module này sẽ lo các chi tiết phức tạp. Tuy nhiên, như một ví dụ, bạn có thể ghi vào tệp log bằng mã tương tự như sau:
def startup():
print("Just a dummy")
def main():
print("Doing the main thing")
return 42
def log(msg):
logfile.write(msg + "\n")
logfile = open("file.log", "w")
log("starting startup")
startup()
log("startup finished")
log("starting main")
ret = main()
log("main finished: " + str(ret))
logfile.close()
6. Sử dụng đệm để kiểm soát việc lưu tệp
Để tránh liên tục mở và lưu cùng một tệp, ví dụ ghi log sử dụng một biến toàn cục và một con trỏ tệp (file handle) tồn tại lâu. Điều này có vẻ ổn trong một ví dụ đơn giản, nhưng trong một tình huống thực tế, chương trình của bạn có thể chạy vô thời hạn và bạn có thể muốn kiểm tra tệp log đó bất cứ lúc nào. Nếu bạn làm vậy, bạn có thể ngạc nhiên:
while True:
log(random.random())
input("Press Enter to continue")
Đoạn mã này mô phỏng việc ghi log định kỳ từ một quy trình chạy dài. Bạn có thể kiểm soát việc ghi log bằng cách nhấn Enter khi bạn muốn ghi thêm một dòng nữa. Tuy nhiên, nếu bạn chạy nó, bạn sẽ nhận thấy một lỗi lớn: nếu bạn nhấn Enter vài lần và kiểm tra tệp log, bạn sẽ thấy không có gì được ghi vào đó!
Lệnh tail
—cụ thể là tail -f
—có thể giúp bạn theo dõi các thay đổi đối với tệp log theo thời gian thực.
Nếu bạn nhấn Enter đủ lần, cuối cùng bạn sẽ thấy một số kết quả vì đầu ra đã vượt quá kích thước bộ đệm mặc định của Python. Trên hệ thống của tôi, kích thước này là 8192 bytes, phải mất một thời gian dài mới tích lũy đủ.
May mắn thay, đối với những trường hợp như thế này, có đối số buffering
, cho phép bạn xác định chính sách đệm. Trong trường hợp tệp log, một cách tiếp cận tuyệt vời là đệm theo dòng (line buffering).
Hãy thử chạy ví dụ trước với một chỉnh sửa nhỏ:
logfile = open("file.log", "w", 1)
Đối số thứ ba, 1
, chỉ định đệm theo dòng. Khi được bật, bạn sẽ thấy tệp log cập nhật mỗi khi hàm log()
chạy vì nó bao gồm ký tự xuống dòng ở cuối khi ghi vào tệp.
7. Chỉ định mã hóa để hỗ trợ UTF-8 đúng cách
Mã hóa ký tự là một chủ đề phức tạp, nhưng sự thống trị của UTF-8 ngày nay có nghĩa là bạn hiếm khi cần phải lo lắng về nó. Tuy nhiên, một số hệ thống cũ có thể sử dụng các mã hóa khác, và bạn không bao giờ biết điều gì có thể phát sinh trong tương lai. Sai sót về mã hóa có thể gây ra những vấn đề lớn.
UTF-16 là một thay thế cho UTF-8, hiệu quả hơn đối với một số loại văn bản nhất định. Hầu hết văn bản viết bằng tiếng Anh phù hợp hơn với UTF-8, nhưng văn bản bằng các ngôn ngữ khác, hoặc các bộ sưu tập ký hiệu—như một tệp chứa đầy emoji—sẽ nhỏ hơn nếu chúng được lưu trữ dưới dạng UTF-16.
Nếu bạn cố gắng mở một tệp UTF-16 bằng cách tiếp cận open
tiêu chuẩn, bạn sẽ thấy một lỗi:
Hàm open
—với một vài lưu ý—mặc định mong đợi mã hóa UTF-8, vì vậy bạn sẽ cần phải chỉ định mã hóa để mở tệp UTF-16:
f = open("../utf16-file.txt", encoding="utf-16")
Bằng cách sử dụng đối số được đặt tên, bạn có thể giữ nguyên đối số mode
và buffering
theo mặc định của chúng. Ngoài ra, bạn có thể cung cấp các giá trị mặc định (hoặc tùy chỉnh) cho chúng:
f = open("../utf16-file.txt", "r", -1, "utf-16")
Ngay cả khi bạn đang mở một tệp UTF-8, bạn nên khai báo rõ ràng mã hóa bằng đối số này. Một số hệ điều hành (ví dụ: Windows) có thể sử dụng mã hóa không phải UTF-8, vì vậy không nên dựa vào giá trị mặc định.
8. Xử lý các tệp bị lỗi định dạng bằng tham số errors
Mặc dù bạn nên cẩn thận chỉ định mã hóa, nhưng điều đó không phải lúc nào cũng khả thi. Tuy nhiên, hàm open
không nhất thiết phải thất bại trong trường hợp xảy ra lỗi mã hóa; bạn có thể sử dụng đối số errors
để chọn hành vi của nó từ một số tùy chọn.
Giá trị mặc định là 'strict'
, sẽ ném ra một ngoại lệ, nhưng bạn có thể hoàn toàn bỏ qua những lỗi đó với 'ignore'
:
f = open("../utf16-file.txt", errors='ignore')
Hạn chế là giờ đây bạn có thể đang xử lý dữ liệu bị hỏng mà không hề hay biết. Việc bạn có thể đối phó với điều này hay không sẽ phụ thuộc vào bản chất dữ liệu của bạn.
Một thay thế phổ biến là thay thế các ký tự không hợp lệ bằng một ký tự cho biết chúng bị thiếu, thường là dấu hỏi. Bạn có thể đã thấy hành vi này trên một số trang web thỉnh thoảng không chỉ định mã hóa đúng cách. Giá trị 'replace'
cho đối số errors
sẽ làm chính xác điều này.
Cuối cùng, giá trị 'backslashreplace'
sẽ thay thế mỗi ký tự bị lỗi định dạng bằng chuỗi thoát (escape sequence) dấu gạch chéo ngược tương đương của nó trong Python. Điều này có thể giúp bạn gỡ lỗi nguyên nhân gốc rễ của vấn đề, vì vậy nó có thể hữu ích cho việc thử nghiệm hoặc là một phần của bộ công cụ phát triển.
9. Kết luận
Hàm open() trong Python là một công cụ mạnh mẽ và linh hoạt, mở ra vô số cách để xử lý tệp tin, từ đọc, ghi dữ liệu đến quản lý tài nguyên hiệu quả với 8 cách sử dụng được hướng dẫn chi tiết. Dù bạn là lập trình viên mới bắt đầu hay đã có kinh nghiệm, việc nắm vững các kỹ thuật này sẽ giúp bạn thao tác với tệp tin một cách chuyên nghiệp, tối ưu hóa mã nguồn và nâng cao hiệu quả dự án. Hy vọng bài viết này đã trang bị cho bạn kiến thức cần thiết để tự tin sử dụng hàm open() và khám phá thêm tiềm năng của Python trong lập trình!
Xem thêm: Hướng dẫn cách hiển thị thời gian trong trung tâm thông báo trên Windows 11
Nếu bạn cần laptop hoặc PC cấu hình mạnh để lập trình Python mượt mà hoặc muốn nâng cấp setup với các phụ kiện công nghệ chất lượng cao, hãy ghé qua COHOTECH – địa chỉ uy tín cung cấp thiết bị công nghệ và dịch vụ hỗ trợ kỹ thuật chuyên nghiệp. Đội ngũ COHOTECH cam kết mang đến giải pháp tối ưu và những ưu đãi hấp dẫn để bạn chinh phục mọi thử thách lập trình. Theo dõi chúng tôi để khám phá thêm nhiều mẹo công nghệ và sản phẩm độc quyền!
Bạn đã áp dụng cách nào của hàm open() trong Python vào dự án của mình chưa? Hãy chia sẻ kinh nghiệm hoặc đặt câu hỏi trong phần bình luận bên dưới nhé! Nếu bài viết này hữu ích, đừng quên like, share và lan tỏa đến bạn bè để cùng làm chủ Python hiệu quả hơn. Cảm ơn bạn đã đọc và hẹn gặp lại!