Các tập tin, thư mục rác luôn là một vấn đề thách thức đối với người dùng máy tính, thay vì sử dụng đến các phần mềm dọn rác từ bên thứ 3, hoặc từ hệ điều hành, sao bạn không thử tự mình làm một phần mềm dọn rác tương tự như vậy nhỉ ?
Vấn đề
Một vấn đề hằng ngày mà bất kỳ người dùng máy tính nào cũng phải đối mặt, đó chính là các tập tin, thư mục rác chiếm dung lượng ổ cứng. Đã là rác thì đương nhiên cần phải xóa bỏ, nhưng việc dọn dẹp rác theo cách thông thường đã quá vô vị đối với bạn? Vậy hôm nay để mình giúp bạn biết thêm một cách 'thú vị' để dọn dẹp rác trong ổ cứng, kể cả những tập tin và thư mục cứng đầu nhất, y như cách crush xóa bỏ tình cảm của bạn dù nó có nhiều đến đâu.
Giải pháp
Đầu tiên, ở mức cơ bản, chúng ta định nghĩa các dữ liệu 'rác' sẽ là các thư mục, tập tin bị trùng lặp. Dựa vào cơ sở này, việc chúng ta cần làm chỉ là tìm ra bản gốc của dữ liệu, sau đó xóa đi những 'bản sao' hay còn nói là những dữ liệu bị trùng lặp.
Thay vì tìm kiếm khắp ổ đĩa để xoá các file trùng lặp, bạn có thể tự động hóa quy trình này bằng cách sử dụng script, bằng cách viết một chương trình để tìm kiếm đệ quy trong ổ đĩa và loại bỏ tất cả các file trùng lặp được tìm thấy.
Nguyên lý hoạt động
Để biết được file này có phải là bản sao của file kia hay khônng, nói cách khác là để biết 2 file này có giống nhau hay không hẳn là ai cũng nghĩ ngay đến cách so sánh nội dung của 2 file này. Đúng, nhưng bằng cách đó, mỗi lần muốn kiểm tra nội dung của 2 file này ta lại phải đọc hết nội dung của nó rồi đệ quy để tìm file có nội dung tương tự, khác nào "mò kim đáy bể", dù là với sức mạnh vượt trội của máy tính thì công việc "mò kim" này sẽ diễn ra nhanh hơn nhiều so với tìm thủ công, nhưng cũng chẳng khấm khá hơn được bao nhiêu.
Vậy giải pháp ở đây là gì? ... Chính là Hashing (băm)!
Giải thích đơn giản về Hashing:
- Hashing là một kỹ thuật áp dụng các quy ước, thuật toán hoặc các công thức toán học để biến đầu vào thành đầu ra tiêu chuẩn. Với hashing chúng ta có thể tạo ra một chuỗi các chữ cái và số nhất định đóng vai trò là danh tính của một File nhất định và nếu chúng ta tìm thấy bất kỳ File nào khác có cùng danh tính, chúng ta sẽ xóa nó.
Có rất nhiều Hash Functions (Hàm băm) khác nhau như:
- md5
- sha1
- sha224, sha256, sha384 và sha512
Nhưng mình sẽ dùng hàm băm md5 và phương thức mã hóa utf-8 để làm ví dụ.
Code:
from hashlib import md5
string = input('Input: ').encode('utf-8')
hashing = md5(string).hexdigest()
print('Output: ', hashing)
Giải thích chút, bạn chỉ cần import
phương thức md5
từ hashlib
để hash và cuối cùng sử dụng hexdigest()
để tạo chuỗi hash.
Lưu ý:
- Hash bằng md5 chỉ hoạt động với xâu đã được mã hóa.
- Đầu vào phải là string, sau khi encode bằng utf-8 thì không phân biệt hoa hay thường, có dấu hay không dấu.
Ví dụ về đầu vào và đầu ra:
//Viết hoa thường lẫn lộn, có dấu
>> Input : "Vũ TùNg Minh"
<< Output : "4e482733aaf13a03c0c81317dba506e9"
//Viết hoa thường lẫn lộn, không dấu
>> Input : "Vu Tung Minh"
<< Output : "75f4482619d338b3deeceff3efb8364e"
//Viết hoa toàn bộ, không dấu
>> Input : "VU TUNG MINH"
<< Output : "00d526aafdf27ccf8100a0efe8ac4643"
//Viết hoa toàn bộ, có dấu
>> Input : "VŨ TÙNG MINH"
<< Output : "d0e03d40da3fe02a32c6c3cb2a510d45"
//Viết thường toàn bộ, có dấu
>> Input : "vũ tùng minh"
<< Output : "047e588a7433f14ab8cc5488807b1153"
//Viết thường toàn bộ, không dấu
>> Input : "vu tung minh"
<< Output : "9a6c2e06b05da0070369ad9866d4de23"
...(vẫn còn rất nhiều trường hợp)
Ví dụ trên đã cho chúng ta thấy cách băm một chuỗi nhưng khi xem xét mối việc này với dự án sắp thực hiện, thì chúng ta phải quan tâm đến các File hơn là chuỗi đúng không? Một câu hỏi khác đã được đặt ra.
Chúng ta hash file như thế nào?
Như ai ai cũng biết bản chất của file cũng chỉ chứa những đoạn nhị phân đại diện cho nội dung của nó, vậy việc chúng ta cần làm sẽ là đọc những đoạn nhị phân ấy và băm nó ra.
Giả sử bạn có tài liệu văn bản đơn giản trên thư mục dự án của mình với tên learn.txt
. Đây là cách mà chúng ta sẽ thực hiện:
from hashlib import md5
with open('learn.txt', 'rb') as file:
content = file.read()
hashing = md5(content).hexdigest()
print(hashing)
Hàm này sẽ trả ra các giá trị băm giống nhau nếu các file đó có nội dung giống nhau khi đó dễ dàng tìm và Xoá các File trùng lặp bằng Python.
Lưu ý: khác tên nhưng giống nội dung thì vẫn trả ra giá trị băm giống nhau nhé.
Nhưng sẽ có thách thức nảy sinh khi chúng ta cố gắng đọc một File khá lớn sẽ mất một lúc để tải nó. Do đó, thay vì đợi toàn bộ File vào bộ nhớ, chúng ta có thể tiếp tục tính toán hàm băm khi đọc File.
Việc tính toán hàm băm trong khi đọc File yêu cầu chúng ta đọc File theo các khối có kích thước nhất định và liên tục cập nhật các hàm băm khi chúng ta tiếp tục đọc File cho đến khi băm hoàn chỉnh toàn bộ File. Nói đơn giản là chia file làm nhiều phần, sau đó đọc từng phần, từng phần đó sẽ được hash, sau khi hash sẽ được update vào biến khác.
Làm theo cách này có thể giúp chúng ta tiết kiệm rất nhiều thời gian chờ đợi mà chúng ta có thể sử dụng để đợi toàn bộ File sẵn sàng.
import hashlib
block_size = 1024
hash = hashlib.md5()
with open('learn.txt', 'rb') as file:
block = file.read(block_size)
while len(block)>0:
hash.update(block)
block = file.read(block_size)
print(hash)
Nhưng đó mới chỉ là tìm ra các bản sao thông qua việc dùng hàm băm, muốn xóa nó chúng ta sẽ sử dụng module OS để xóa các bản sao.
Để xóa một file hoặc thư mục bằng thư viện OS, chúng ta sẽ dùng hàm remove()
import os
'''Hàm listdir() là để in ra màn hình những thư mục và tập tin đang có trong thư mục hiện tại '''
print(os.listdir())
"<< Output : ['main.py', 'learn.txt', '.upm']"
os.remove('learn.txt')
print(os.listdir())
"<< Output : ['main.py', '.upm']"
Sau khi đã xoá được file với hàm remove(), chúng ta sẽ bắt đầu xây dựng ứng dụng.
Cách tạo ứng dụng xoá các File trùng lặp
Những thư viện cần thiết:
import time
import os
from hashlib import sha256
Lúc nãy để ví dụ mình đã dùng hàm băm md5, nhưng nó thực sự không được khuyến khích dùng cho lắm, ngược lại thì hàm băm sha256 đang rất được ưa chuộng nên mình sẽ dùng nó.
Đây sẽ là sườn của chương trình.
import time
import os
from hashlib import sha256
class Duplython:
def __init__(self):
self.home_dir = os.getcwd()
self.File_hashes = []
self.Cleaned_dirs = []
self.Total_bytes_saved = 0
self.block_size = 65536
self.count_cleaned = 0
def welcome(self):
print('******************************************************************')
print('**************** DUPLYTHON ****************************')
print('********************************************************************\n')
print('---------------- WELCOME ----------------------------')
time.sleep(3)
print('\nCleaning .................')
def main(self):
self.welcome()
if __name__ == '__main__':
App = Duplython()
App.main()
Đó chỉ là giao diện của chương trình, khi bạn chạy nó sẽ chỉ in lời chào mừng ra màn hình.
$ python3 app.py
******************************************************************
**************** DUPLYTHON ****************************
********************************************************************
---------------- WELCOME ----------------------------
Cleaning .................
class Duplython:
def __init__(self):
self.home_dir = os.getcwd()
self.File_hashes = []
self.Cleaned_dirs = []
self.Total_bytes_saved = 0
self.block_size = 65536
self.count_cleaned = 0
def welcome(self):
print('******************************************************************')
print('**************** DUPLYTHON ****************************')
print('********************************************************************\n')
print('---------------- WELCOME ----------------------------')
time.sleep(3)
print('\nCleaning .................')
def generate_hash(self, Filename):
Filehash = sha256()
try:
with open(Filename, 'rb') as File:
fileblock = File.read(self.block_size)
while len(fileblock)>0:
Filehash.update(fileblock)
fileblock = File.read(self.block_size)
Filehash = Filehash.hexdigest()
return Filehash
except:
return False
def main(self):
self.welcome()
if __name__ == '__main__':
App = Duplython()
App.main()
Triển khai logic cho chương trình
Sau khi tạo hàm băm File, chúng ta phải triển khai ở nơi sẽ so sánh các chuỗi băm đó và loại bỏ bất kỳ bản sao nào được tìm thấy.
Tôi sẽ tạo một hàm đơn giản được gọi là clean()
như hình bên dưới.
def clean(self):
all_dirs = [path[0] for path in os.walk('.')]
for path in all_dirs:
os.chdir(path)
All_Files =[file for file in os.listdir() if os.path.isfile(file)]
for file in All_Files:
filehash = self.generate_hash(file)
if not filehash in self.File_hashes:
if filehash:
self.File_hashes.append(filehash)
else:
byte_saved = os.path.getsize(file); self.count_cleaned+=1
self.Total_bytes_saved+=byte_saved
os.remove(file); filename = file.split('/')[-1]
print(filename, '.. cleaned ')
os.chdir(self.home_dir)
Mình đã tạo ra hàm Cleaning_summary()
chỉ để làm việc đó. In kết quả của quá trình dọn dẹp ra màn hình để hoàn thành chương trình.
def cleaning_summary(self):
mb_saved = self.Total_bytes_saved/1048576
mb_saved = round(mb_saved, 2)
print('\n\n--------------FINISHED CLEANING ------------')
print('File cleaned : ', self.count_cleaned)
print('Total Space saved : ', mb_saved, 'MB')
print('-----------------------------------------------')
Toàn bộ mã nguồn sẽ trông như sau:
class Duplython:
def __init__(self):
self.home_dir = os.getcwd()
self.File_hashes = []
self.Cleaned_dirs = []
self.Total_bytes_saved = 0
self.block_size = 65536
self.count_cleaned = 0
def welcome(self):
print('******************************************************************')
print('**************** DUPLYTHON ****************************')
print('********************************************************************\n')
print('---------------- WELCOME ----------------------------')
time.sleep(3)
print('\nCleaning .................')
def generate_hash(self, Filename):
Filehash = sha256()
try:
with open(Filename, 'rb') as File:
fileblock = File.read(self.block_size)
while len(fileblock)>0:
Filehash.update(fileblock)
fileblock = File.read(self.block_size)
Filehash = Filehash.hexdigest()
return Filehash
except:
return False
def clean(self):
all_dirs = [path[0] for path in os.walk('.')]
for path in all_dirs:
os.chdir(path)
All_Files =[file for file in os.listdir() if os.path.isfile(file)]
for file in All_Files:
filehash = self.generate_hash(file)
if not filehash in self.File_hashes:
if filehash:
self.File_hashes.append(filehash)
else:
byte_saved = os.path.getsize(file); self.count_cleaned+=1
self.Total_bytes_saved+=byte_saved
os.remove(file); filename = file.split('/')[-1]
print(filename, '.. cleaned ')
os.chdir(self.home_dir)
def cleaning_summary(self):
mb_saved = self.Total_bytes_saved/1048576
mb_saved = round(mb_saved, 2)
print('\n\n--------------FINISHED CLEANING ------------')
print('File cleaned : ', self.count_cleaned)
print('Total Space saved : ', mb_saved, 'MB')
print('-----------------------------------------------')
def main(self):
self.welcome();self.clean();self.cleaning_summary()
if __name__ == '__main__':
App = Duplython()
App.main()
Ứng dụng Xoá các File trùng lặp bằng Python của chúng ta đã hoàn tất, bây giờ để chạy ứng dụng, hãy chạy nó trong thư mục cụ thể mà bạn muốn dọn dẹp và nó sẽ đệ quy qua một thư mục nhất định để tìm tất cả các File và xóa File trùng lặp.
Để thử chương trình, mình viết thêm một chương trình nữa để tạo ra các bản sao có nội dung như nhau:
trashs = int(input('Số lượng file rác: '))
for i in range(trashs):
file = open(r'file' + str(i) + '.txt', 'w', encoding = 'utf-8')
file.write('<3 Thư <3')
file.close()
(Các bạn đừng để ý nội dung của file đó :333)
Sau khi tạo ra được một mớ file rác rồi thì mình thử chạy chương trình dọn rác thôi.
Lời kết
Không chỉ có rác máy tính mới cần phải dọn dẹp, mà ngoài cuộc sống kia cũng có vô số những đống rác đang làm xấu đi môi trường của chúng ta, ảnh hưởng nặng nề đối với mẹ thiên nhiên. Vì một môi trường xanh, sạch, đẹp, và vì lợi ích lâu dài ảnh hưởng đến sự tồn vong của loài người. Hãy cùng chung tay dọn dẹp rác thải <3 Như cái cách crush dọn dẹp mớ tình cảm của bạn dành cho cô ấy vậy =(((
Cảm ơn các bạn đã đón xem, hy vọng bài viết giúp ích được phần nào trong con đường học lập trình của mọi người :33
Nguồn: codelearn.io