2011-03-18 67 views
26

考慮下面的Python代碼過濾文件?在這種特殊情況下,我想要以* .png,*。gif,* .jpg或* .jpeg結尾的所有文件。使用fnmatch.filter由多於一個可能的文件擴展名

現在我來到了

for root, dirs, files in os.walk(directory): 
    for extension in ['jpg', 'jpeg', 'gif', 'png']: 
     for filename in fnmatch.filter(files, '*.' + extension): 
      pass 

但我認爲這是不是很優雅和高性能。

有人有更好的主意嗎?

+0

應該是好的,但一個'tuple'會在這裏更好的(挑剔!)'( 'JPG', 'JPEG', 'GIF', 'PNG')'。 – user225312 2011-03-18 12:12:18

+4

@A A:爲什麼在這種情況下元組更好? – tyrondis 2011-03-18 12:16:37

回答

35

如果你只需要檢查的擴展(即沒有進一步的通配符),你爲什麼不乾脆用基本的字符串操作?

for root, dirs, files in os.walk(directory): 
    for filename in files: 
     if filename.endswith(('.jpg', '.jpeg', '.gif', '.png')): 
      pass 
+0

謝謝 - 這是一個相當明顯的解決方案 - 但我沒有看到它=) – tyrondis 2011-03-18 12:44:30

+4

請注意,這種方法是區分大小寫的,例如名爲'annoying.GIF文件'不會被包含在上面的例子中。 這可以通過標準化文件名來解決:'... if filename.lower()。endswith(('.jpg','.jpeg','.gif','.png'))...' – asherbar 2016-04-25 06:03:27

3

這不是真正的優雅下去,但它的工作原理:

for root, dirs, files in os.walk(directory): 
    for filename in fnmatch.filter(files, '*.png') + fnmatch.filter(files, '*.jpg') + fnmatch.filter(files, '*.jpeg') + fnmatch.filter(files, '*.gif'): 
     pass 
3

這將是一個更好的辦法,也許是因爲你沒有打電話+反覆使用tuple代替list

for root, dirs, files in os.walk(directory): 
    for extension in ('*.jpg', '*.jpeg', '*.gif', '*.png'): 
     for filename in fnmatch.filter(files, extension): 
      pass 

A tuple更好,因爲您創建它們後不打算修改擴展名。你只是用它來遍歷它們。

8

我認爲你的代碼其實很好。如果你想摸摸每名只有一次,定義自己的過濾功能:

def is_image_file(filename, extensions=['.jpg', '.jpeg', '.gif', '.png']): 
    return any(filename.endswith(e) for e in extensions) 

for root, dirs, files in os.walk(directory): 
    for filename in filter(is_image_file, files): 
     pass 
+0

你確定這會有所作爲嗎?爲什麼不定義一個元組(它只會被創建一次,對吧?)而不用擔心這一切? (只是問!) – user225312 2011-03-18 12:21:20

+0

@AA:在你的代碼中,元組將在外循環的每次迭代中創建。在我的代碼中,列表只會創建一次。我不認爲這裏的性能差異是相關的。我的建議更多地是關於代碼可讀性 - 你的也很好。 – 2011-03-18 12:25:22

+0

真的。我只是想確定。 – user225312 2011-03-18 12:25:59

6

我一直在使用它,並取得了很多成功。

import fnmatch 
import functools 
import itertools 
import os 

# Remove the annotations if you're not on Python3 
def find_files(dir_path: str=None, patterns: [str]=None) -> [str]: 
    """ 
    Returns a generator yielding files matching the given patterns 
    :type dir_path: str 
    :type patterns: [str] 
    :rtype : [str] 
    :param dir_path: Directory to search for files/directories under. Defaults to current dir. 
    :param patterns: Patterns of files to search for. Defaults to ["*"]. Example: ["*.json", "*.xml"] 
    """ 
    path = dir_path or "." 
    path_patterns = patterns or ["*"] 

    for root_dir, dir_names, file_names in os.walk(path): 
     filter_partial = functools.partial(fnmatch.filter, file_names) 

     for file_name in itertools.chain(*map(filter_partial, path_patterns)): 
      yield os.path.join(root_dir, file_name) 

實例:

for f in find_files(test_directory): 
    print(f) 

收率:

.\test.json 
.\test.xml 
.\test.ini 
.\test_helpers.py 
.\__init__.py 

測試使用多種模式:

for f in find_files(test_directory, ["*.xml", "*.json", "*.ini"]): 
    print(f) 

收率:

.\test.json 
.\test.xml 
.\test.ini 
0

這是我用來過濾apache日誌目錄中的文件。 在這裏,我排除錯誤flles

rep_filters = [now.strftime("%Y%m%d")] 
def files_filter(liste_fic, filters = rep_filters): 
    s = "(fic for fic in liste_fic if fic.find('error') < 0" 
    for filter in filters: 
     s += " and fic.find('%s') >=0 " % filter 
    s += ")" 
    return eval(s) 
相關問題