Kỹ Thuật Cơ Bản Làm Việc Với Tập Tin Và Thư Mục Trong Python

Kỹ Thuật Cơ Bản Làm Việc Với Tập Tin Và Thư Mục Trong Python

Trong các dự án phần mềm, không thể tránh được việc thao tác với file/folder vì bản chất các tập tin vẫn là loại thông dụng nhất để lưu trữ thông tin, đặc biệt là các file chứa cấu hình hệ thống, cấu hình phần mềm. Các ngôn ngữ lập trình đều cung cấp các thư viện, câu lệnh, các cách thức để thao tác với các đối tượng file và folder. Tuy nhiên, với nhiều lập trình viên (trong đó có cả tôi) thi thoảng vẫn tự tìm kiếm một số thao tác tưởng như đơn giản vô cùng để xử lý tệp tin.

Ví dụ: Lấy đường dẫn tuyệt đối đến file cấu hình để truyền vào các controller thực hiện việc load cấu hình.
Bài viết dưới đây sẽ liệt kê một số kỹ thuật hữu ích và thường gặp khi làm việc với file/folder trong Python.

1. Lấy thông tin đường dẫn đến file/thư mục.

Khi làm việc với file/folder, các lập trình viên Python thường sẽ sử dụng lib có sẵn là os và path.
Để lấy đường dẫn của thư mục hiện tại, chúng ta có thể tham khảo câu lệnh sau:

import os

current_directory = os.getcwd()
print("Current directory: '{}', type of {}".format(current_directory, type(current_directory)))


Với hệ điều hành Windows:

Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 23:03:10) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> print(platform.system())
Windows
>>>
>>> import os
>>> current_directory = os.getcwd()
>>> print("Current directory: '{}', type of {}".format(current_directory, type(current_directory)))
Current directory: 'E:\code_learn\Scripts', type of <class 'str'>

Với hệ điều hành Linux (hoặc các *UNIX khác):

Python 3.6.9 (default, Jul 17 2020, 12:50:27)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> platform.system()
'Linux'
>>>
>>> import os
>>> current_directory = os.getcwd()
>>> print("Current directory: '{}', type of {}".format(current_directory, type(current_directory)))
Current directory: '/home/quangvinh1986', type of <class 'str'>

Điều khác biệt giữa 2 hệ điều hành là dấu phân cách giữa các thư mục, file:
Với Windows là dấu \ (backward slash, downward slash, and reverse solidus)
Với Linux là dấu / (forward slash, upward slash and solidus)

Đây là điều cần lưu ý với các lập trình viên khi thực hiện lập trình trên một hệ điều hành thông dụng như Windows và triển khai phần mềm trên một hệ điều hành khác (Ubuntu, CentOS, ...), phần đường dẫn đến file/folder phải có phần tùy chỉnh theo hệ điều hành. 

2. Liệt kê danh sách các file/folder bên trong một thư mục.

Để lấy danh sách file/folder của thư mục hiện tại, dùng function os.listdir().

>>> os.listdir()
['20200924.py', '20200925.txt', 'code', 'my_python', 'my_text']
>>> # Liệt kê danh sách file/folder trong thư mục con cấp một
>>> os.listdir('code')
['20200924_code.py', '20200925_code.txt', 'back_up']
>>> # Liệt kê danh sách file/folder trong thư mục con cấp hai
>>> os.listdir('code\\back_up')
['20200924_backup_code.py', '20200925_backup_code.txt']

Câu lệnh os.listdir('code\\back_up') hoạt động được trên Windows, nếu chuyển sang chạy trên hệ điều hành Linux sẽ báo lỗi tại vị trí '\\' do quy ước đường dẫn giữa 2 hệ điều hành khác nhau.
Để giải quyết được việc này, chúng ta sẽ dùng đến một function khác để lấy đường dẫn tuyệt đối của thư mục.

>>> backup_path = os.path.join(os.getcwd(), 'code', 'back_up')
>>> backup_path
'E:\\code_learn\\Scripts\\code\\back_up'
>>> os.listdir(backup_path)
['20200924_backup_code.py', '20200925_backup_code.txt']

3. Tạo mới một thư mục

Để tạo mới một thư mục, sử dụng function os.mkdir('new_folder_name')

>>> os.mkdir('new_folder')
>>> os.listdir()
['20200924.py', '20200925.txt', 'code', 'my_python', 'my_text', 'new_folder']

Để tạo thư mục mới bên trong thư mục 'code', cần sử dụng cách nối tên thư mục như ở trên.

>>> new_code_path = os.path.join(os.getcwd(),'code', 'new_code_folder')
>>> new_code_path
'E:\\code_learn\\Scripts\\code\\new_code_folder'
>>> os.mkdir(new_code_path)
>>> os.listdir('code')
['20200924_code.py', '20200925_code.txt', 'back_up', 'new_code_folder']

Nếu thư mục đã tồn tại mà vẫn tạo lại thư mục, sẽ có lỗi xảy ra

>>> os.mkdir(new_code_path)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileExistsError: [WinError 183] Cannot create a file when that file already exists: 'E:\\code_learn\\Scripts\\code\\new_code_folder'

--> Khi thực hiện tạo thư mục nên chú ý việc handler lỗi . FileExistsError và một số các lỗi khác liên quan đến File/Folder là subclass của nhóm lỗi OSError (https://docs.python.org/3.3/library/exceptions.html#os-exceptions), nên chúng ta có thể handler cả cụm lỗi.


>>> try:
... os.mkdir(new_code_path)
... except OSError as error:
... print(error)
...
[WinError 183] Cannot create a file when that file already exists: 'E:\\code_learn\\Scripts\\code\\new_code_folder'

4. Kiểm tra một file/thư mục có tồn tại hay không?

Ở ví dụ dưới đây, trong thư mục hiện tại, chúng ta có thư mục 'code', không có file 'check_exist.py', kết quả kiểm tra như bên dưới

>>> os.listdir()
['20200924.py', '20200925.txt', 'code', 'my_python', 'my_text', 'new_folder']
>>> os.path.exists('code')
True
>>> os.path.exists('20200924.py')
True
>>> os.path.exists('check_exist.py')
False

Tương tự, kiểm tra thư mục 'new_code_folder' có trong thư mục con 'code' hay không ?


>>> os.listdir('code')
['20200924_code.py', '20200925_code.txt', 'back_up', 'new_code_folder']
>>> new_code_path = os.path.join(os.getcwd(),'code', 'new_code_folder')
>>> os.path.exists(new_code_path)
True

Kiểm tra input vào có là folder?

>>> os.listdir()
['20200924.py', '20200925.txt', 'code', 'my_python', 'my_text', 'new_folder']
>>> os.path.isdir('code')
True
>>> os.path.isdir('20200924.py')
False

Kiểm tra đầu vào có là file?


>>> os.listdir()
['20200924.py', '20200925.txt', 'code', 'my_python', 'my_text', 'new_folder']
>>> os.path.isfile('code')
False
>>> os.path.isfile('20200924.py')
True

Nếu file/folder không tồn tại thì kết quả trả về là False

>>> os.path.isfile('not_found.py')
False
>>> os.path.isdir('not_found_folder')
False

5. Xóa file/folder.

Ví dụ dưới đây sẽ thực hiện xóa file có tên `20200925.txt` và folder có tên `new_folder`

>>> os.listdir()
['20200924.py', '20200925.txt', 'code', 'my_python', 'my_text', 'new_folder']
>>> os.remove('20200925.txt')
>>> os.listdir()
['20200924.py', 'code', 'my_python', 'my_text', 'new_folder']

>>> os.rmdir('new_folder')
>>> os.listdir()
['20200924.py', 'code', 'my_python', 'my_text']

6. Sao chép một file.

Trong module os, cung cấp một function có tên popen để thực hiện copy file nhưng function này chạy trên Windows và Linux khác nhau.

import os

# Windows
os.popen('copy file1.txt file6.txt')

# Unix
os.popen('cp file1.txt file6.txt')

Cá nhân tôi thường không sử dụng function này trong chương trình khi cần thực hiện copy/paste file. Tôi sẽ sử dụng module shutil kết hợp với os khi cần copy đến các đường dẫn sâu hơn.
Có nhiều cách sử dụng để sao chép file bàng shutil, mỗi cách có một đặc điểm, kết quả khác nhau về metadata của file, các cách thức được mô tả tại đường dẫn: https://docs.python.org/3/library/shutil.html.args

Thông thường, khi không cần quá chú trọng vào việc metadata, mà chỉ cần copy dữ liệu là đủ, chúng ta chỉ cần dùng lệnh shutil.copyfile

>>> os.listdir()
['20200924.py', 'code', 'my_python', 'my_text']
>>> import shutil
>>> shutil.copyfile('20200924.py', '20200924_copy.py')
'20200924_copy.py'
>>> os.listdir()
['20200924.py', '20200924_copy.py', 'code', 'my_python', 'my_text']

7. Đổi tên/Di chyển vị trí một file.

Giống như lệnh mv của bash/shell thì module os hỗ trợ việc rename/move một file bằng cùng một lệnh: os.rename. Như ví dụ dưới đây, thực hiện đổi tên file 20200924.py thành 20200925.py


>>> os.listdir()
['20200924.py', '20200924_copy.py', 'code', 'my_python', 'my_text']
>>> os.rename('20200924.py', '20200925.py')
>>> os.listdir()
['20200924_copy.py', '20200925.py', 'code', 'my_python', 'my_text']

Di chuyển file sang thư mục khác.

>>> os.listdir()
['20200924_copy.py', '20200925.py', 'code', 'my_python', 'my_text']
>>> new_path = os.path.join(os.getcwd(),'code', '20200925.py')
>>> os.listdir('code')
['20200924_code_1.py', '20200925_code.txt', 'back_up', 'new_code_folder']
>>> os.rename('20200925.py', new_path)
>>> os.listdir()
['20200924_copy.py', 'code', 'my_python', 'my_text']
>>> os.listdir('code')
['20200924_code_1.py', '20200925.py', '20200925_code.txt', 'back_up', 'new_code_folder']

Kết luận:

Trên đây là một số lệnh Python cơ bản để làm việc với file/folder. Tôi hy vọng bài viết này sẽ đóng vai trò như một tài liệu tham khảo nhanh cho các bạn khi cần thiết. Ngoài module os ra, các bạn cũng có thể sử dụng module pathlib với những tính năng tương tự.
Cảm ơn các bạn đã đọc bài viết.