python 實現文件內容去重
文本內容去重有很多很簡單的方法可以實現,很多編輯器自帶去除重複行的功能。寫這篇文章的原因主要有兩個
- 有的文本文件很大,超出了編譯器能讀取的範圍
- 能有代碼解決的代碼解決,寫好代碼可以在其他代碼中調用,更方便使用
簡單的可以分爲兩種情況小文件和大文件,先來看小文件去重實現。如同把大象關冰箱一樣分三步:
- 第一步,讀取文件每一行,並處理掉換行符
- 第二步,將文件內容去重
- 第三步,寫到新文件裏(把冰箱門關上)
上代碼
def file_remove_same(input_file, output_file):
"""
針對小文件去重
:param input_file: 輸入文件
:param out_file: 去重後出文件
:return:
"""
with open(input_file, 'r', encoding='utf8') as f, open(output_file, 'a', encoding='utf8') as ff:
data = [item.strip() for item in f.readlines()] # 針對最後一行沒有換行符,與其他它行重複的情況
new_data = list(set(data))
ff.writelines([item + '\n' for item in new_data if item]) # 針對去除文件中有多行空行的情況
對於大文件幾十個G那種(更大的也別放在本地了,放數據庫)就不能加載到內存中了,強行加載到內存中直接報內存錯誤
解決方案是:將文件按行讀取,根據內容生成一個指紋(md5值或者其他唯一可識別的值),將指紋存集合中,當逐行讀取的過程中判斷集合中是否已經含有該行元素的指紋。如果指紋沒有添加到集合中,則添加指紋到集合中並將此行追加輸出到輸出文件中。如果指紋已經在集合中了,說明此行與上面的某一行重複。
def gen_md5(data):
"""
生成md5
:param data: 字符串數據
:return:
"""
md5 = hashlib.md5()
md5.update(data.encode('utf-8'))
return md5.hexdigest()
def big_file_remove_same(input_file, output_file):
"""
針對大文件文件去重(將文件文件寫在一行的,沒有辦法去重)
:param input_file:
:param output_file:
:return:
"""
finger_print_set = set()
with open(input_file, 'r', encoding='utf8') as f, open(output_file, 'w', encoding='utf8') as ff:
for line in f:
line_string = line.strip()
finger_print = gen_md5(line_string)
if finger_print not in finger_print_set:
finger_print_set.add(finger_print)
ff.write(line)
這樣解決大小文件去重的問題
還有一種極端情況,就是指紋集合非常大,將內存佔用溢出。這種情況幾乎不會遇到,做一個大致的估計:當這個指紋集合內存佔用到3G的時候,按照集合的佔用效率大致是67%算,就能容納2G的指紋,指紋按照md5值計算,就能容納6710萬行數據 。如果文件超過6710萬行可以考慮採用數據庫(redis)方案。數據庫方案有空再補充吧