web-dev-qa-db-ja.com

Glob()を使用してファイルを再帰的に検索する方法

これは私が持っているものです:

glob(os.path.join('src','*.c'))

しかし、私はsrcのサブフォルダを検索したいのです。このような何かがうまくいくでしょう:

glob(os.path.join('src','*.c'))
glob(os.path.join('src','*','*.c'))
glob(os.path.join('src','*','*','*.c'))
glob(os.path.join('src','*','*','*','*.c'))

しかし、これは明らかに限られていて不格好です。

599
Ben Gartner

Python 3.5+

新しいPythonを使っているので、 pathlib モジュールの pathlib.Path.glob を使うべきです。

from pathlib import Path

for filename in Path('src').glob('**/*.c'):
    print(filename)

Pathlibを使用したくない場合は、 glob.glob を使用してください。ただし、recursiveキーワードパラメータを忘れずに渡してください。

一致するファイルがドット(。)で始まる場合。カレントディレクトリのファイルやUnixベースのシステムの隠しファイルのように、以下の os.walk ソリューションを使用してください。

古いPythonのバージョン

古いPythonバージョンでは、 os.walk を使用してディレクトリを再帰的に検索し、 fnmatch.filter を使用して単純な式と照合します。

import fnmatch
import os

matches = []
for root, dirnames, filenames in os.walk('src'):
    for filename in fnmatch.filter(filenames, '*.c'):
        matches.append(os.path.join(root, filename))
1127
Johan Dahlin

他のソリューションと似ていますが、os.walkはすでにファイル名をリストしているので、globの代わりにfnmatch.fnmatchを使用します。

import os, fnmatch


def find_files(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            if fnmatch.fnmatch(basename, pattern):
                filename = os.path.join(root, basename)
                yield filename


for filename in find_files('src', '*.c'):
    print 'Found C source:', filename

また、ジェネレータを使用すると、すべてのファイルを見つけてからそれらを処理するのではなく、見つかったとおりに各ファイルを処理できます。

103
Bruno Oliveira

Globモジュールを再帰的globbingの**をサポートするように修正しました。

>>> import glob2
>>> all_header_files = glob2.glob('src/**/*.c')

https://github.com/miracle2k/python-glob2/ /

ユーザに**構文を使用する機能を提供したい場合、つまりos.walk()だけでは十分ではない場合に役立ちます。

59
miracle2k

Python 3.4から、**ワイルドカードをサポートする新しい pathlib モジュールのPathクラスの1つの glob() メソッドを使うことができます。例えば:

from pathlib import Path

for file_path in Path('src').glob('**/*.c'):
    print(file_path) # do whatever you need with these files

更新: Python 3.5以降、glob.glob()でも同じ構文がサポートされています。

55
taleinat
import os
import fnmatch


def recursive_glob(treeroot, pattern):
    results = []
    for base, dirs, files in os.walk(treeroot):
        goodfiles = fnmatch.filter(files, pattern)
        results.extend(os.path.join(base, f) for f in goodfiles)
    return results

fnmatchglob とまったく同じパターンを与えるので、これは非常に近い意味でglob.globの本当に素晴らしい置き換えです。 glob.iglobの代わりになる繰り返しバージョン(ジェネレータなど)は、簡単な適応です(最後に返される1つの結果リストをyieldする代わりに、単に中間結果をextendにする)。

39
Alex Martelli

あなたの基準に合うファイル名を集めるのにos.walkを使いたいでしょう。例えば:

import os
cfiles = []
for root, dirs, files in os.walk('src'):
  for file in files:
    if file.endswith('.c'):
      cfiles.append(os.path.join(root, file))
20
Geoff Reedy

これは、ネストされたリスト内包表記、globの代わりにos.walk、および単純なサフィックスマッチングを使用した解決策です。

import os
cfiles = [os.path.join(root, filename)
          for root, dirnames, filenames in os.walk('src')
          for filename in filenames if filename.endswith('.c')]

それはワンライナーに圧縮することができます:

import os;cfiles=[os.path.join(r,f) for r,d,fs in os.walk('src') for f in fs if f.endswith('.c')]

または関数として一般化

import os

def recursive_glob(rootdir='.', suffix=''):
    return [os.path.join(looproot, filename)
            for looproot, _, filenames in os.walk(rootdir)
            for filename in filenames if filename.endswith(suffix)]

cfiles = recursive_glob('src', '.c')

完全なglobスタイルのパターンが必要な場合は、AlexとBrunoの例に従って、fnmatchを使用してください。

import fnmatch
import os

def recursive_glob(rootdir='.', pattern='*'):
    return [os.path.join(looproot, filename)
            for looproot, _, filenames in os.walk(rootdir)
            for filename in filenames
            if fnmatch.fnmatch(filename, pattern)]

cfiles = recursive_glob('src', '*.c')
14
akaihola

最近私は拡張子.jpgを付けて写真を復元しなければなりませんでした。 Photcを実行して、膨大な種類の拡張子を持つ、2209個のファイルを含む4579個のディレクトリを復元しました。

#!/usr/binenv python2.7

import glob
import shutil
import os

src_dir = "/home/mustafa/Masaüstü/yedek"
dst_dir = "/home/mustafa/Genel/media"
for mediafile in glob.iglob(os.path.join(src_dir, "*", "*.jpg")): #"*" is for subdirectory
    shutil.copy(mediafile, dst_dir)
5
Mustafa Çetin

JohanとBrunoは、述べられているように、最低限の要件について優れたソリューションを提供しています。私は、このようなより複雑なシナリオを扱うことができるAnt FileSet and Globs を実装する Formic をリリースしました。あなたの要件の実装は以下のとおりです。

import formic
fileset = formic.FileSet(include="/src/**/*.c")
for file_name in fileset.qualified_files():
    print file_name
5
Andrew Alcock

他の答えに基づいて、これは私の現在の実用的な実装で、これはルートディレクトリのネストされたxmlファイルを取得します。

files = []
for root, dirnames, filenames in os.walk(myDir):
    files.extend(glob.glob(root + "/*.xml"))

私は本当にPythonを楽しんでいます:)

5
daveoncode

Globモジュールだけを使ってそれを行う別の方法です。 rglobメソッドに開始ベースディレクトリと一致するパターンをシードするだけで、一致するファイル名のリストが返されます。

import glob
import os

def _getDirs(base):
    return [x for x in glob.iglob(os.path.join( base, '*')) if os.path.isdir(x) ]

def rglob(base, pattern):
    list = []
    list.extend(glob.glob(os.path.join(base,pattern)))
    dirs = _getDirs(base)
    if len(dirs):
        for d in dirs:
            list.extend(rglob(os.path.join(base,d), pattern))
    return list
3
chris-piekarski

それはfnmatchか正規表現を使います:

import fnmatch, os

def filepaths(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            try:
                matched = pattern.match(basename)
            except AttributeError:
                matched = fnmatch.fnmatch(basename, pattern)
            if matched:
                yield os.path.join(root, basename)

# usage
if __== '__main__':
    from pprint import pprint as pp
    import re
    path = r'/Users/hipertracker/app/myapp'
    pp([x for x in filepaths(path, re.compile(r'.*\.py$'))])
    pp([x for x in filepaths(path, '*.py')])
2
hipertracker

提案された答えに加えて、あなたはいくつかの怠惰な世代とリスト内包表記の魔法でこれをすることができます:

import os, glob, itertools

results = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.c'))
                                               for root, dirs, files in os.walk('src'))

for f in results: print(f)

1行に収まり、メモリ内の不要なリストを避けることに加えて、これにはNice副作用があります。**演算子と同じように使用できます。たとえば、すべてを取得するにはos.path.join(root, 'some/path/*.c')を使用できます。この構造を持つsrcのすべてのサブディレクトリにある.cファイル。

2
fxx

これを作成しました..それは階層的な方法でファイルとディレクトリを印刷します

しかし私はfnmatchやwalkを使っていません

#!/usr/bin/python

import os,glob,sys

def dirlist(path, c = 1):

        for i in glob.glob(os.path.join(path, "*")):
                if os.path.isfile(i):
                        filepath, filename = os.path.split(i)
                        print '----' *c + filename

                Elif os.path.isdir(i):
                        dirname = os.path.basename(i)
                        print '----' *c + dirname
                        c+=1
                        dirlist(i,c)
                        c-=1


path = os.path.normpath(sys.argv[1])
print(os.path.basename(path))
dirlist(path)
2
Shaurya Gupta

pathlib.rglob() を考えてください。

これは、与えられた相対パターンの前に"**/"を追加してPath.glob()を呼び出すのと同じです。

import pathlib


for p in pathlib.Path("src").rglob("*.c"):
    print(p)

@ taleinatに関連した post こちらや以前の post こちらも参照してください。

1
pylang

これはリスト内包表記を使ってディレクトリとすべてのサブディレクトリで multiple file extensions recursively を検索する方法です。

import os, glob

def _globrec(path, *exts):
""" Glob recursively a directory and all subdirectories for multiple file extensions 
    Note: Glob is case-insensitive, i. e. for '\*.jpg' you will get files ending
    with .jpg and .JPG

    Parameters
    ----------
    path : str
        A directory name
    exts : Tuple
        File extensions to glob for

    Returns
    -------
    files : list
        list of files matching extensions in exts in path and subfolders

    """
    dirs = [a[0] for a in os.walk(path)]
    f_filter = [d+e for d in dirs for e in exts]    
    return [f for files in [glob.iglob(files) for files in f_filter] for f in files]

my_pictures = _globrec(r'C:\Temp', '\*.jpg','\*.bmp','\*.png','\*.gif')
for f in my_pictures:
    print f
1
sackpower

fnmatch を除いたJohan Dahlinの答えの簡略版。

import os

matches = []
for root, dirnames, filenames in os.walk('src'):
  matches += [os.path.join(root, f) for f in filenames if f[-2:] == '.c']
1
flowfree

python> = .5 の場合、**recursive=Trueを使用できます。

import glob
for x in glob.glob('path/**/*.c', recursive=True):
    print(x)

デモ


Recursiveがtrueの場合、パターン**はすべてのファイルと0個以上のdirectoriesおよびsubdirectoriesに一致します。パターンの後にos.sepが続く場合、ディレクトリとsubdirectoriesのみが一致します。

1
Pedro Lobito

あるいはリスト内包表記では:

 >>> base = r"c:\User\xtofl"
 >>> binfiles = [ os.path.join(base,f) 
            for base, _, files in os.walk(root) 
            for f in files if f.endswith(".jpg") ] 
1
xtofl

これは、ベースファイル名だけでなく、フルパスに対してパターンを一致させる解決策です。

fnmatch.translate を使用してglobスタイルのパターンを正規表現に変換します。この正規表現は、ディレクトリをたどっている間に見つかった各ファイルのフルパスと照合されます。

re.IGNORECASEはオプションですが、ファイルシステム自体では大文字と小文字が区別されないため、Windowsでは望ましいです。 (私は正規表現をコンパイルするのに面倒なことはしませんでした。ドキュメントは内部的にキャッシュされるべきだと書いているからです。)

import fnmatch
import os
import re

def findfiles(dir, pattern):
    patternregex = fnmatch.translate(pattern)
    for root, dirs, files in os.walk(dir):
        for basename in files:
            filename = os.path.join(root, basename)
            if re.search(patternregex, filename, re.IGNORECASE):
                yield filename
0
yoyo

python 3.5以降の場合

file_names_array = glob.glob('src/*.c', recursive=True)

編集:@NeStackのガイドに従って上記がうまくいかない場合は、試してください

file_names_array = glob.glob('src/**.c', recursive=True)

さらにあなたが必要かもしれません

for full_path_in_src in  file_names_array:
    print (full_path_in_src ) # be like 'abc/xyz.c'
    #Full system path of this would be like => 'path till src/abc/xyz.c'
0
Sami
import sys, os, glob

dir_list = ["c:\\books\\heap"]

while len(dir_list) > 0:
    cur_dir = dir_list[0]
    del dir_list[0]
    list_of_files = glob.glob(cur_dir+'\\*')
    for book in list_of_files:
        if os.path.isfile(book):
            print(book)
        else:
            dir_list.append(book)
0
serega386

私はこの投稿の一番上の答えを修正しました..そして最近、与えられたディレクトリ(searchdir)とその下のサブディレクトリの中のすべてのファイルをループするスクリプトを作成しました。サイズ。

これが誰かに役立つことを願っています...そして彼らはディレクトリを歩いてfileinfoを取得することができます。

import time
import fnmatch
import os

def fileinfo(file):
    filename = os.path.basename(file)
    rootdir = os.path.dirname(file)
    lastmod = time.ctime(os.path.getmtime(file))
    creation = time.ctime(os.path.getctime(file))
    filesize = os.path.getsize(file)

    print "%s**\t%s\t%s\t%s\t%s" % (rootdir, filename, lastmod, creation, filesize)

searchdir = r'D:\Your\Directory\Root'
matches = []

for root, dirnames, filenames in os.walk(searchdir):
    ##  for filename in fnmatch.filter(filenames, '*.c'):
    for filename in filenames:
        ##      matches.append(os.path.join(root, filename))
        ##print matches
        fileinfo(os.path.join(root, filename))
0
ihightower

私は python 2.x のための解決策を必要としていました 速い ​​大きなディレクトリで/。
私はこれを思いつきました:

import subprocess
foundfiles= subprocess.check_output("ls src/*.c src/**/*.c", Shell=True)
for foundfile in foundfiles.splitlines():
    print foundfile

lsが一致するファイルを見つけられない場合には、何らかの例外処理が必要になるかもしれないことに注意してください。

0
Roman