Bài 7. Thao tác với file dữ liệu
Tác giả: Hoàng Anh Quân
Phần tóm tắt nội dung bài viết sử dụng cây thư mục được minh họa dưới đây
mainFolder/
folderA/
main.py
data.txt
folderB/
Trong toàn bộ bài viết, ta sử dụng thuật ngữ terminal để gọi chung cho terminal trên Linux và command prompt trên Windows.
1. Đường dẫn
Để tham chiếu đến một file/thư mục nào đó trong cây thư mục, ta cần truyền vào đường dẫn tới file/thư mục đó. Có hai loại đường dẫn: đường dẫn tuyệt đối và đường dẫn tương đối.
Trong mục này, ta sẽ minh hoạ kiến thức về đường dẫn thông qua việc thực thi chương trình trong file main.py
bằng nhiều cách khác nhau.
Cách thực hiện đơn giản nhất là mở một terminal tại thư mục folderA
rồi chạy câu lệnh
python main.py
1.1. Đường dẫn tương đối
Câu lệnh viết ở trên minh họa một cách thực thi chương trình sử dụng đường dẫn tương đối. Cụ thể, đường dẫn tương đối của một file dữ liệu là cách di chuyển từ vị trí hiện tại của terminal tới file đó.
Vị trí hiện tại của terminal thường được thể hiện trong terminal. Ví dụ như trong terminal dưới đây
quanhoang@laptop (04:20:00) ~/OptimaLab/mainFolder $
thì thư mục hiện tại của terminal này là mainFolder.
Ngoài ra, khoảng trống sau dấu $
là nơi để viết câu lệnh.
Có thể truy xuất vị trí hiện tại của terminal thông qua câu lệnh (chạy trên hệ điều hành Linux) echo $PWD
. Một câu trả lời trên stack overflow có thông tin về câu lệnh tương ứng cho hệ điều hành Windows.
Trong một đường dẫn tương đối, ta sử dụng dấu ..
để đi chuyển lên thư mục cha và sử dụng trực tiếp tên thư mục con để truy cập thư mục con đó. Ba ví dụ dưới đây thể hiện cách thực thi file main.py
qua đường dẫn tương đối từ ba vị trí terminal khác nhau.
- Nếu terminal đang ở thư mục
folderA
, câu lệnh cần thực hiện làpython main.py
- Nếu terminal đang ở thư mục
mainFolder
, câu lệnh cần thực hiện (đối với từng hệ điều hành) làpython folderA/main.py # Linux python folderA\main.py # Windows
- Nếu terminal đang ở thư mục
folderB
, câu lệnh cần thực hiện (đối với từng hệ điều hành) làpython ../folderA/main.py # Linux python ..\folderA\main.py # Windows
1.2. Đường dẫn tuyệt đối
Đường dẫn tuyệt đối xuất phát từ gốc của cây thư mục và di chuyển tới file cần tham chiếu.
python /path/to/mainFolder/folderA/main.py # Linux
python D:\path\to\mainFolder\folderA\main.py # Windows
Đường dẫn tuyệt đối có ưu điểm là bất biến với vị trí của terminal. Tức là, để tham chiếu tới một file bất kỳ, người dùng có thể sử dụng cùng một đường dẫn tuyệt đối, bất kể vị trí hiện tại của terminal.
Đổi lại ưu điểm này, đường dẫn tuyệt đối thường dài và chứa thông tin cá nhân của người sử dụng. Sẽ không hay lắm nếu có đường dẫn mang nội dung dưới đây
python /home/trash/mimpython/main.py
1.3. Lời khuyên về đặt tên
Để thuận lợi trong quá trình lập trình, tên của các file, thư mục nên tuân thủ quy tắc ba không:
- Không chứa dấu tiếng Việt (sắc, huyền, hỏi, ngã, nặng)
- Không chứa dấu cách
- Không chứa kí tự đặc biệt (ví dụ như
?, :, +, -, *, (, ), [, ]
)
2. Đọc file
Giả sử file data.txt
có nội dung dưới đây
MIM
Python
2022
Để đọc nội dung của file trên, file main.py
nên được thiết kế như sau
path = 'data.txt'
with open(path, 'r') as f:
allLines = f.read().splitlines() # ['MIM', 'Python', '2022']
Phần nội dung xuất hiện sau dấu comment #
thể hiện output khi thực hiện hàm print()
cho biến tương ứng.
Một vài bình luận về việc đọc file
-
Để thực hiện chương trình trong
main.py
, người dùng cần chuyển đường dẫn tới thư mụcfolderA.
-
Biến
path
là đường dẫn tới file dữ liệudata.txt
, hiện là một đường dẫn tương đối. Mốc khi xét đường dẫn tương đối luôn là vị trị hiện tại của terminal, chứ không phải là vị trí của filemain.py
. -
Biến
path
có thể được thay bởi một đường dẫn tuyệt đối tới filedata.txt
. - Một số cách khác để tạo biến
allLines
chứa thông tin của tất cả các dòng trong file dữ liệu# cách thứ nhất with open(path, 'r') as f: allLines = f.readlines() # ['MIM\n', 'Python\n', '2022\n'] # cách thứ hai with open(path, 'r') as f: allLines = list(f) # ['MIM\n', 'Python\n', '2022\n']
Với hai cách này, người dùng nên sử dụng hàm
rstrip()
để loại bỏ ký tự\n
ở cuối mỗi phần tử. - Hàm
split()
liên quan chặt chẽ tới việc xử lý file dữ liệu.splitedList = 'this_is_nothing'.split('_') # ['this', 'is', 'nothing']
- Có một cách khác để đọc file mà không sử dụng cấu trúc
with ... as ...
f = open('data.txt', 'r') allLines = f.read().splitlines() f.close()
Tuy nhiên, người mới bắt đầu lập trình không được khuyến khích sử dụng cách này.
3. Tạo file
Sau khi xóa file data.txt
, cấu trúc thư mục hiện tại là
mainFolder/
folderA/ (vị trí hiện tại)
main.py
folderB/
image.png
Khi thực thi file main.py
với nội dung
# the first edit: create a new file data.txt and write 2 lines into it
with open('data.txt', 'w') as f: # line 1
f.write('mim\npython') # line 2
# the second edit: append content to the existing file, not overwrite it
with open('data.txt', 'a') as f: # line 3
f.write('2022') # line 4
ta thu được file data.txt
trong thư mục folderA
với nội dung
mim
python2022
Một số câu hỏi liên quan
-
Giả sử file
data.txt
đã tồn tại từ trước. Hỏi trong đoạn code bên trên, nội dung hiện có sẽ bị mất khi chương trình thực thi tới dòng 1 (câu lệnhwith
) hay khi tới dòng 2 (câu lệnhf.write
)? -
Chuyện gì sẽ xảy ra nếu ta chạy dòng 3 và dòng 4, bỏ qua dòng 1 và dòng 2? Tức là sử dụng tham số
a
trong cấu trúcwith open
khi file chưa tồn tại.
Một vài bình luận về việc tạo file
-
Khi sử dụng câu lệnh
open(fileName, 'w')
, nội dung có từ trước trong filefileName
sẽ bị mất. -
Một tình huống sử dụng tính năng viết bổ sung vào một file có sẵn (
with open(fileName, 'a')
) là khi cập nhật log trong quá trình hoạt động của một chương trình. -
Khi viết nội dung vào một file, ta thường dùng hàm
join()
để viết nhiều dòng dữ liệu trong cùng một câu lệnh.with open('data.txt', 'w') as f: dataList = ['fire', 'water', 'wood', 'metal', 'earth'] f.write('\n'.join(dataList))
4. Tạo thư mục
Khi thực thi file main.py
chứa nội dung dưới đây
path = 'subFolder/newData.txt'
with open(path, 'w') as f:
f.write('MIM')
ta nhận được thông báo lỗi
FileNotFoundError: [Errno 2] No such file or directory: 'subFolder/newData.txt'
Sở dĩ có lỗi này là do thư mục (dự kiến sẽ) chứa file ta định tạo, thư mục subFolder
, chưa tồn tại. Ta phải tạo thư mục này trước khi tạo file trong đó. Có ít nhất ba cách thực hiện công việc này
-
Lệnh
mkdir
trên Linux. Có thể tham khảo câu lệnhtldr mkdir
để nắm được hướng dẫn sử dụng của lệnh này. - Thư viện
os
trong Pythonimport os folderName = 'example_directory/subFolder/subSubFolder' os.makedirs(folderName, exist_ok = True)
- Thư viện
pathlib
trong Pythonfrom pathlib import Path folderName = 'example_directory/subFolder/subSubFolder' folder = Path(folderName) folder.mkdir(exist_ok = True)
Thông thường, ta tạo một
Path
instance là file cần tạo rồi sử dụngfilePath.parent
để biết cha của file đang xét.filePath = Path('subFolder/newData.txt') parentFolder = filePath.parent parentFolder.mkdir(exist_ok = True)
Nội dung trên chỉ là tóm tắt, học viên cần đọc các tài liệu liệt kê trong phần tài liệu tham khảo dưới đây.
Tài liệu tham khảo
Tài liệu chính
- PythonCrashCourse (trang 183-193)
Tài liệu bổ sung
- Bài viết về xử lý file trên trang web Real Python
- Bài viết về thư viện pathlib trên trang web Real Python