2012-10-29 59 views
2

我也+20 000文件,看起來像這樣的下面,都在同一個目錄下保存最新的文件:查找重複的文件名,並且僅使用python

8003825.pdf 
8003825.tif 
8006826.tif 

怎樣才能找到所有重複的文件名,而忽略文件擴展名。

說明:我指的是一個副本,即具有相同文件名的文件,而忽略文件擴展名。我做照顧,如果該文件是不是100%相同(例如HASHSIZE或類似的東西。)

例如:

"8003825" appears twice 

然後看每個重複文件的元數據,並且只保留最新的一個。

這個帖子類似:

Keep latest file and delete all other

我想我必須創建所有文件的列表,檢查文件是否已經存在。如果是這樣,那麼使用os.stat來確定修改日期?

我有點擔心加載所有這些文件名到內存中。而且不知道是否有辦事更Python的方式...

的Python 2.6 Windows 7的

+5

我不'不要以爲你應該關心將20000甚至200000個文件名加載到內存中。 –

回答

7

你可以用O(n)複雜做到這一點。具有sort的解決方案具有O(n*log(n))複雜性。

import os 
from collections import namedtuple 

directory = #file directory 
os.chdir(directory) 

newest_files = {} 
Entry = namedtuple('Entry',['date','file_name']) 

for file_name in os.listdir(directory): 
    name,ext = os.path.splitext(file_name) 
    cashed_file = newest_files.get(name) 
    this_file_date = os.path.getmtime(file_name) 
    if cashed_file is None: 
     newest_files[name] = Entry(this_file_date,file_name) 
    else: 
     if this_file_date > cashed_file.date: #replace with the newer one 
      newest_files[name] = Entry(this_file_date,file_name) 

newest_files是具有不帶擴展名與持有文件的完整文件名和修改日期命名的元組的值的鍵文件名的dictonary。如果遇到的新文件位於字典中,則將其日期與存儲在字典中的日期進行比較,並在必要時進行替換。

最後你有一個包含最新文件的字典。

然後,您可以使用此列表執行第二遍。請注意,字典中的查找複雜度爲O(1)。因此查看字典中所有n文件的整體複雜度爲O(n)

例如,如果你想只留下最新的文件具有相同的名稱,並刪除其他的,這可以通過以下方式獲得:

for file_name in os.listdir(directory): 
    name,ext = os.path.splitext(file_name) 
    cashed_file_name = newest_files.get(name).file_name 
    if file_name != cashed_file_name: #it's not the newest with this name 
     os.remove(file_name) 

至於建議的Blckknght在評論中,你甚至可以避免第二遍,並刪除舊文件,只要加入一行代碼:

else: 
     if this_file_date > cashed_file.date: #replace with the newer one 
      newest_files[name] = Entry(this_file_date,file_name) 
      os.remove(cashed_file.file_name) #this line added 
+0

+1不錯!它只在內存中保存它需要的文件,並且是O(n)。 – Ant

+1

你甚至可以一舉通過。每次將文件的年齡與緩存的年齡進行比較時,請立即刪除較舊的文件。在單次傳遞結束時,您只能爲每個名稱留下最新的文件。 – Blckknght

+0

@Blckknght你是對的! – ovgolovin

1

首先,獲取文件名列表,並對其進行排序。這將把任何重複的東西放在一起。

然後,剝離文件擴展名並與鄰居比較,os.path.splitext()itertools.groupby()在此處可能會有用。

一旦你分組了重複,選擇一個你想繼續使用os.stat()

最終你的代碼可能看起來是這樣的:

import os, itertools 

files = os.listdir(base_directory) 
files.sort() 
for k, g in itertools.groupby(files, lambda f: os.path.splitext(f)[0]): 
    dups = list(g) 
    if len(dups) > 1: 
     # figure out which file(s) to remove 

你不應該在這裏擔心內存,你看一對夫婦兆字節的數量級上的東西。

0

對於文件名計數器,你可以使用一個defaultdict存儲每個文件出現了多少次:

​​
+0

目錄中的文件將被排序,他爲什麼要計數它們? – kreativitea

+1

@kreativitea因爲引用來自:http://docs.python.org/2/library/os.html#os.listdir - '返回一個列表,其中包含路徑給出的目錄中的條目名稱。該列表以任意順序排列。它不包括特殊條目''。'和'..',即使它們出現在目錄中。' –

+0

是的,但我的意思是你會使用'sorted(os.listdir(directory))',並避免創建一個全新的字典。在已排序的列表上迭代,創建具有相同名稱的文件列表,掃描組以及重置鏈看起來效率更高。 – kreativitea