Kiểm tra các tệp trùng lặp Python

Đôi khi chúng tôi cần tìm các tệp trùng lặp trong hệ thống tệp của mình hoặc trong một thư mục cụ thể. Trong hướng dẫn này, chúng ta sẽ viết mã một tập lệnh Python để làm điều này. Tập lệnh này hoạt động trong Python 3. x

Chương trình sẽ nhận một thư mục hoặc danh sách các thư mục để quét, sau đó sẽ duyệt qua các thư mục đã cho và tìm các tệp trùng lặp trong các thư mục đó

Chương trình này sẽ tính toán hàm băm cho mọi tệp, cho phép chúng tôi tìm các tệp trùng lặp mặc dù tên của chúng khác nhau. Tất cả các tệp mà chúng tôi tìm thấy sẽ được lưu trữ trong một từ điển, với hàm băm là khóa và đường dẫn đến tệp là giá trị. { hash: [list of paths] }

Để bắt đầu, hãy import thư viện os, syshashlib

[python]
nhập hệ điều hành
nhập hệ thống
nhập hashlib
[/python]

Sau đó, chúng ta cần một hàm để tính hàm băm MD5 của một tệp nhất định. Hàm nhận đường dẫn đến tệp và trả về thông báo HEX của tệp đó

[python]
def hashfile(path, blocksize = 65536).
afile = open(path, 'rb')
hasher = hashlib. md5()
buf = afile. read(blocksize)
trong khi len(buf) > 0.
máy băm. cập nhật(buf)
buf = afile. đã đọc (kích thước khối)
afile. close()
trả lại hàm băm. hexdigest()
[/python]

Bây giờ chúng tôi cần một chức năng để quét một thư mục cho các tệp trùng lặp

[python]
def findDup(parentFolder).
# Dups ở định dạng {hash. [names]}
dups = {}
for dirName, subdirs, fileList trong os. đi bộ(parentFolder).
print('Đang quét %s. ' % dirName)
cho tên tệp trong fileList.
# Lấy đường dẫn đến tệp
path = os. con đường. join(dirName, filename)
# Tính hàm băm
file_hash = hashfile(path)
# Thêm hoặc nối thêm đường dẫn tệp< .
if file_hash in dups:
dups[file_hash]. nối thêm(đường dẫn)
else.
dups[file_hash] = [path]
return dups
[/python]

Hàm findDup đang sử dụng os.walk để duyệt qua thư mục đã cho. Nếu bạn cần một hướng dẫn toàn diện hơn về nó, hãy xem bài viết Cách duyệt qua cây thư mục trong Python. Hàm os.walk chỉ trả về tên tệp, vì vậy chúng tôi sử dụng os.path.join để lấy đường dẫn đầy đủ đến tệp. Sau đó, chúng tôi sẽ lấy hàm băm của tệp và lưu trữ nó vào từ điển dups

Khi findDup duyệt xong thư mục, nó sẽ trả về một từ điển chứa các tệp trùng lặp. Nếu chúng ta duyệt qua một số thư mục, chúng ta cần một phương thức để hợp nhất hai từ điển

[python]
# Nối hai từ điển
def joinDicts(dict1, dict2).
cho khóa trong dict2. phím().
if khóa trong dict1.
dict1[key] = dict1[key] + dict2[key]
else.
dict1[key] = dict2[key]
[/python]

import0 lấy 2 từ điển, lặp qua từ điển thứ hai và kiểm tra xem khóa có tồn tại trong từ điển đầu tiên không, nếu nó tồn tại, phương thức sẽ nối các giá trị trong từ điển thứ hai với các giá trị trong từ điển thứ nhất. Nếu khóa không tồn tại, nó sẽ lưu nó trong từ điển đầu tiên. Ở cuối phương thức, từ điển đầu tiên chứa tất cả thông tin

Để có thể chạy tập lệnh này từ dòng lệnh, chúng tôi cần nhận các thư mục dưới dạng tham số, sau đó gọi findDup cho mọi thư mục

[python]
if __name__ == '__main__'.
if len(sys. argv) > 1.
dups = {}
folders = sys. argv[1. ]
cho tôi trong thư mục.
# Lặp lại các thư mục đã cho
if os. con đường. tồn tại (tôi).
# Tìm các tệp trùng lặp và nối chúng vào bản sao
joinDicts(dups, findDup(i))
else.
print('%s không phải là đường dẫn hợp lệ, vui lòng xác minh' % i)
sys. exit()
printResults(dups)
else.
print('Sử dụng. python dupFinder. thư mục py hoặc python dupFinder. py folder1 folder2 folder3')
[/python]

Hàm import2 xác minh rằng thư mục đã cho tồn tại trong hệ thống tệp. Để chạy tập lệnh này, hãy sử dụng import3. Cuối cùng, chúng ta cần một phương thức để in kết quả

Đây có phải là hình ảnh tương tự? . Tôi đoán hầu hết các bạn đã ở trong một tình huống như thế này. Và như bạn có thể biết, có thể mất thời gian để xác định thủ công tất cả các tệp trùng lặp. Vì vậy, ở đây chúng ta sẽ khám phá một tùy chọn để tự động xác định các tệp trùng lặp trong Python

Nhưng trước khi chúng ta bắt đầu & nói ngắn gọn. Nếu bạn chỉ quan tâm đến mã chứ không phải giải thích về cách xác định các tệp trùng lặp, bạn có thể truy cập thẳng vào kho lưu trữ Github và bắt đầu dọn dẹp hệ thống của mình. Nếu không thì… Hãy xem nó hoạt động như thế nào

Tìm tập tin trùng lặp

Làm cách nào chúng tôi có thể tự động hóa quá trình xác định các tệp trùng lặp? . Vì vậy, chúng ta nên xem qua một số lựa chọn và sau đó quyết định chúng ta muốn đi theo con đường nào

  1. Cách dễ nhất là chỉ cần tìm các tệp có tên giống hệt nhau. Tuy nhiên, chúng tôi có thể bỏ lỡ các bản sao trong trường hợp bản sao tệp được tạo dưới một tên mới. Ngoài ra, nó có thể nguy hiểm vì các tệp có tên giống hệt nhau có thể chứa thông tin hoàn toàn khác nhau. Ví dụ. Nếu bạn chụp ảnh bằng điện thoại thông minh của mình, bạn có thể đã nhấp vào ảnh có tên IMG_0001. jpg. Tuy nhiên tôi nghi ngờ nó giống như tôi đã lấy
  2. Nhưng những gì về kích thước tập tin? . Thậm chí nhiều khả năng, các tệp có kích thước giống hệt nhau sẽ không chứa cùng một nội dung
  3. Chà, vậy tại sao chúng ta không xem xét nhiều tính năng? . Ngoài ra, chúng tôi sẽ bỏ lỡ các tệp trùng lặp với các tên khác nhau một lần nữa

Vì vậy, không có cơ hội để tìm các tệp trùng lặp trên ổ cứng của chúng tôi một cách đáng tin cậy? . Nhưng nó không dựa trên các tham số như tên tệp, kích thước, v.v. Thay vào đó, chúng tôi sẽ so sánh trực tiếp nội dung của các tệp. Cách tiếp cận đơn giản nhất ở đây là so sánh hai tệp từng chút một. Điều này sẽ hoạt động và chúng tôi chắc chắn 100% rằng các tệp là bản sao của nhau. Tuy nhiên, làm điều này cho mọi cặp tệp có thể có thể tốn kém về mặt tính toán tùy thuộc vào kích thước và số lượng tệp chúng tôi muốn kiểm tra. May mắn thay, có một mẹo chúng ta có thể chơi ở đây. Thay vì so sánh mọi thứ từng chút một, chúng tôi có thể tính toán các số nhận dạng duy nhất cho từng tệp và sau đó so sánh chúng thay vì toàn bộ tệp. Một cách phổ biến để truy xuất các số nhận dạng như vậy là các hàm băm mật mã

Khái niệm hàm băm mật mã

Trước khi chúng ta đi vào khái niệm về hàm băm mật mã, hãy lùi lại một bước và suy nghĩ về những tính năng mà chúng ta muốn định danh của mình có

  1. Các định danh phải là duy nhất. Chúng tôi sẽ không có ích gì nếu hai tệp khác nhau có cùng mã định danh
  2. Các số nhận dạng phải được sao chép. Chúng tôi không muốn có số nhận dạng ngẫu nhiên, nghĩa là nếu chúng tôi tạo lại số nhận dạng cho cùng một tệp, chúng tôi muốn nhận được kết quả giống hệt nhau. Nếu không, chúng tôi không thể sử dụng nó để tìm các bản sao

Tốt cho chúng tôi rằng cả hai yêu cầu của chúng tôi đã được đáp ứng bởi các hàm băm. Yêu cầu đầu tiên được gọi là khả năng chống va chạm. Điều này có thể không đúng với từng hàm băm trong bất kỳ tình huống nào nhưng trong ngữ cảnh của chúng ta, chúng ta có thể giả định rằng hàm băm mà chúng ta sẽ sử dụng sau này là không có xung đột. Yêu cầu thứ hai là tạo cùng một mã định danh cho cùng một tệp mỗi khi chúng tôi tính toán, đó cũng là yêu cầu chung đối với các hàm băm - chúng mang tính xác định. Ngoài ra, các hàm băm là các hàm một chiều, có nghĩa là với hàm băm, không thể xây dựng lại đầu vào đã tạo ra hàm băm. Thuộc tính này mở ra một loạt các ứng dụng nằm ngoài phạm vi của bài viết này, bao gồm cả việc sử dụng chúng trong các loại tiền điện tử như Bitcoin

Khái niệm hàm băm mật mã chỉ có thể được phác thảo đại khái ở đây, nhưng các tài nguyên giải thích chi tiết có sẵn ở nơi khác (e. g. đây, đây hoặc đây). Trong các hàm băm ngắn lấy các chuỗi dữ liệu có độ dài khác nhau và ánh xạ chúng vào một mảng bit có độ dài cố định. Vì các tệp trên ổ cứng của chúng tôi có kích thước khác nhau nên chúng tôi sẽ cắt chúng thành các khối, sau đó chạy khối đầu tiên thông qua hàm băm, nối hàm băm trung gian vào khối tiếp theo và chạy lại khối đó thông qua hàm (cập nhật). Chúng tôi làm như vậy cho đến khi tất cả các khối đã được xử lý. Nếu khối cuối cùng ngắn hơn độ dài khối đã xác định, phần đệm sẽ được áp dụng để đảm bảo độ dài khối không đổi. Quá trình này cũng được phác thảo trong Hình 1 bên dưới. Nói chung, đầu vào, ở đây là tệp quan tâm, được gọi là thông báo trong khi đầu ra của hàm băm được gọi là thông báo

Hình 1. Phác thảo sơ bộ về tính toán băm

Triển khai bằng Python

Vì vậy, bây giờ chúng ta đã hiểu rất sơ bộ về các hàm băm mật mã, chúng ta có thể tiếp tục và sử dụng chúng để xác định các tệp trùng lặp trên đĩa cứng của chúng ta

Nếu bạn muốn xem toàn bộ quá trình triển khai hoặc trực tiếp bắt đầu sử dụng nó, hãy truy cập kho lưu trữ Github hoặc cài đặt nó bằng pip

pip install duplicate-finder

Trước tiên, chúng ta cần tạo một hàm tính toán hàm băm cho bất kỳ tệp nào. Phép tính sẽ sử dụng hàm băm sha256 có trong thư viện hashlib của Pythons. Như bạn có thể thấy từ khối mã bên dưới, nó tuân theo những gì chúng tôi đã mô tả trong Hình 1. Đầu tiên, tệp quan tâm được mở, một khối có độ dài cố định được đọc, bản tóm tắt được cập nhật, sau đó khối tiếp theo được đọc từ tệp, bản tóm tắt được cập nhật lại, v.v. và cứ tiếp tục như vậy cho đến khi toàn bộ tệp được xử lý

Bây giờ chúng ta có thể sử dụng chức năng trên cùng với một chức năng khác thu thập thông tin qua tất cả các thư mục con của một thư mục quan tâm. Nó sẽ trả về hàm băm cho mỗi tệp dưới dạng Pandas DataFrame và có tùy chọn hạn chế tìm kiếm đối với các tệp có phần mở rộng cụ thể, chẳng hạn. jpg

Vì kết quả là một Khung dữ liệu Pandas, chúng tôi có thể tiếp tục và sử dụng phương thức sẵn có của Pandas để tìm các bản sao. Kết quả sẽ lại là một DataFrame nhưng lần này nó chỉ chứa các tệp trùng lặp, được sắp xếp theo hàm băm của chúng. Ngoài ra, chúng tôi có tùy chọn xuất kết quả dưới dạng. tệp csv

Tuy nhiên, trong một số trường hợp, chúng tôi có thể không quan tâm đến tất cả các bản sao nhưng muốn biết liệu có bản sao nào của một tệp cụ thể hay không. Chúng ta có thể làm điều này với gói Python tìm trùng lặp như sau

Cuối cùng, trong một số trường hợp, chúng tôi muốn so sánh hai thư mục với nhau và kiểm tra các bản sao. Điều này cũng có thể dễ dàng thực hiện với gói công cụ tìm trùng lặp của chúng tôi

Phần kết luận

Tìm các tệp trùng lặp trong và trên các thư mục là một nhiệm vụ dễ giải quyết bằng Python. Mặc dù dữ liệu meta như tên và kích thước tệp không phù hợp với tác vụ này và việc so sánh từng bit có thể chậm, nhưng việc sử dụng các hàm băm mật mã mang lại một cách hiệu quả để tiến lên phía trước. Ở đây chúng tôi đã sử dụng hàm băm sha256. Tuy nhiên, các thuật toán băm khác có thể dễ dàng được đưa vào khung

Vì vậy, nếu bạn chưa thực hiện, bạn có thể xem mã hoàn chỉnh cho bài viết này tại đây, theo dõi tôi trên Twitter hoặc kết nối qua LinkedIn