glob.glob 모듈을 사용하여 하위 폴더를 검색하려면 어떻게해야합니까?


107

폴더에서 일련의 하위 폴더를 열고 일부 텍스트 파일을 찾고 텍스트 파일의 일부 줄을 인쇄하고 싶습니다. 나는 이것을 사용하고있다 :

configfiles = glob.glob('C:/Users/sam/Desktop/file1/*.txt')

그러나 이것은 하위 폴더에도 액세스 할 수 없습니다. 누구든지 동일한 명령을 사용하여 하위 폴더에 액세스하는 방법을 알고 있습니까?


답변:


163

Python 3.5 이상에서는 새로운 재귀 **/기능을 사용합니다 .

configfiles = glob.glob('C:/Users/sam/Desktop/file1/**/*.txt', recursive=True)

recursive가 설정 되면 **경로 구분 기호가 0 개 이상의 하위 디렉토리와 일치합니다.

이전 Python 버전에서는 glob.glob()하위 디렉토리의 파일을 재귀 적으로 나열 할 수 없습니다.

이 경우 대신 다음 os.walk()과 같이 사용 fnmatch.filter()합니다.

import os
import fnmatch

path = 'C:/Users/sam/Desktop/file1'

configfiles = [os.path.join(dirpath, f)
    for dirpath, dirnames, files in os.walk(path)
    for f in fnmatch.filter(files, '*.txt')]

이것은 디렉토리를 재귀 적으로 걷고 모든 절대 경로 이름을 일치하는 .txt파일로 반환 합니다. 이 특정 경우에는 fnmatch.filter()과잉 일 수 있으며 .endswith()테스트를 사용할 수도 있습니다 .

import os

path = 'C:/Users/sam/Desktop/file1'

configfiles = [os.path.join(dirpath, f)
    for dirpath, dirnames, files in os.walk(path)
    for f in files if f.endswith('.txt')]

3
내가 볼 수있는 것은 : glob.glob ( '/ path to directory / * / *. txt ") 저를 위해 일하고 있습니다. 이것은 기본적으로 Unix 쉘 규칙을 사용하고 있습니다.
Surya

7
@ User123 : 디렉토리를 재귀 적으로 나열하지 않습니다 . 모든 텍스트 파일을 한 수준 깊이 로 나열 하지만 추가 하위 디렉터리 나 path to directory.
Martijn Pieters

1
이것은 완전히 관련이 없지만 기능 recursive=False과 함께 설정 **/하면 주어진 폴더에있는 파일 목록이 아니라 하위에있는 파일 목록을 제공하는 이유는 무엇입니까?
Dr_Zaszuś 15:08에

@ Dr_Zaszuś : 죄송합니다? **/목록 제공 디렉토리 이름 의 패턴 종료 때문에, 현재 작업 디렉토리를 /, 그리고와 recursive=False당신은 기본적으로 두 번이 *아니라 그냥 같은 일치, */단지 덜 효율적.
Martijn Pieters

@ Dr_Zaszuś : */*모든 하위 디렉토리의 모든 파일이 필요한 경우 사용 합니다.
Martijn Pieters

22

바로 아래의 하위 디렉터리에서 파일을 찾으려면 :

configfiles = glob.glob(r'C:\Users\sam\Desktop\*\*.txt')

모든 하위 디렉토리를 순회하는 재귀 버전의 경우 Python 3.5부터 사용 **하고 전달할 수 있습니다 .recursive=True

configfiles = glob.glob(r'C:\Users\sam\Desktop\**\*.txt', recursive=True)

두 함수 호출 모두 목록을 반환합니다. glob.iglob()경로를 하나씩 반환 하는 데 사용할 수 있습니다 . 또는 다음을 사용하십시오pathlib .

from pathlib import Path

path = Path(r'C:\Users\sam\Desktop')
txt_files_only_subdirs = path.glob('*/*.txt')
txt_files_all_recursively = path.rglob('*.txt') # including the current dir

두 메서드 모두 반복자를 반환합니다 (경로를 하나씩 가져올 수 있음).


예, 이해했습니다. 하지만 glob()디렉토리에서 패턴을 지원할 것이라고는 예상하지 못했습니다 .
Martijn Pieters

댓글이 삭제되었습니다. 이제 잘못된 인상을 받았습니다. 게다가 패치에는 **재귀 사례에 대한 문서 업데이트가 포함되어 있습니다. 그러나 **작동 하려면 스위치 btw 를 설정 해야 합니다 recursion=True.
Martijn Pieters

20

이 주제에 대해 많은 혼란이 있습니다. 내가 그것을 명확히 할 수 있는지 보자 (Python 3.7) :

  1. glob.glob('*.txt') :현재 디렉토리에서 '.txt'로 끝나는 모든 파일과 일치합니다.
  2. glob.glob('*/*.txt') :1과 동일
  3. glob.glob('**/*.txt') :'.txt'로 끝나는 모든 파일은 바로 아래 하위 디렉토리에서만 일치 하지만 현재 디렉토리에서는 일치하지 않습니다.
  4. glob.glob('*.txt',recursive=True) :1과 동일
  5. glob.glob('*/*.txt',recursive=True) :3과 동일
  6. glob.glob('**/*.txt',recursive=True):현재 디렉토리 및 모든 하위 디렉토리에서 '.txt'로 끝나는 모든 파일과 일치합니다.

따라서 항상 지정하는 것이 가장 좋습니다. recursive=True.


1
이것이 최고의 답변이어야합니다!
Abhik 사카

17

glob2의 패키지는 와일드 카드를 지원하며 합리적으로 빠르게

code = '''
import glob2
glob2.glob("files/*/**")
'''
timeit.timeit(code, number=1)

내 랩톱에서는 60,000 개 이상의 파일 경로 를 일치시키는 데 약 2 초가 걸립니다 .


9

Python 2.6에서 Formic 을 사용할 수 있습니다.

import formic
fileset = formic.FileSet(include="**/*.txt", directory="C:/Users/sam/Desktop/")

공개-나는이 패키지의 작성자입니다.


4

여기서 수있는 적합한 버전 glob.glob없이 같은 기능은 glob2.

def find_files(directory, pattern='*'):
    if not os.path.exists(directory):
        raise ValueError("Directory not found {}".format(directory))

    matches = []
    for root, dirnames, filenames in os.walk(directory):
        for filename in filenames:
            full_path = os.path.join(root, filename)
            if fnmatch.filter([full_path], pattern):
                matches.append(os.path.join(root, filename))
    return matches

따라서 다음과 같은 dir 구조가 있다면

tests/files
├── a0
   ├── a0.txt
   ├── a0.yaml
   └── b0
       ├── b0.yaml
       └── b00.yaml
└── a1

다음과 같이 할 수 있습니다.

files = utils.find_files('tests/files','**/b0/b*.yaml')
> ['tests/files/a0/b0/b0.yaml', 'tests/files/a0/b0/b00.yaml']

fnmatch파일 이름 만이 아니라 전체 파일 이름 자체에 대해 거의 패턴이 일치합니다.


2

configfiles = glob.glob('C:/Users/sam/Desktop/**/*.txt")

모든 경우에 작동하지 않고 대신 glob2를 사용합니다.

configfiles = glob2.glob('C:/Users/sam/Desktop/**/*.txt")

2

glob2 패키지를 설치할 수 있다면 ...

import glob2
filenames = glob2.glob("C:\\top_directory\\**\\*.ext")  # Where ext is a specific file extension
folders = glob2.glob("C:\\top_directory\\**\\")

모든 파일 이름 및 폴더 :

all_ff = glob2.glob("C:\\top_directory\\**\\**")  

2

Python 3.4 이상을 실행중인 경우 pathlib모듈을 사용할 수 있습니다 . 이 Path.glob()방법은 **"이 디렉토리 및 모든 하위 디렉토리, 재귀 적으로"를 의미 하는 패턴을 지원합니다 . Path일치하는 모든 파일에 대해 개체를 생성하는 생성기를 반환 합니다.

from pathlib import Path
configfiles = Path("C:/Users/sam/Desktop/file1/").glob("**/*.txt")

0

Martijn이 지적했듯이 glob은 **Python 3.5에 도입 된 연산자 를 통해서만이를 수행 할 수 있습니다 . OP가 명시 적으로 glob 모듈을 요청했기 때문에 다음은 유사하게 작동하는 지연 평가 반복기를 반환합니다.

import os, glob, itertools

configfiles = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.txt'))
                         for root, dirs, files in os.walk('C:/Users/sam/Desktop/file1/'))

configfiles하지만이 접근 방식에서는 한 번만 반복 할 수 있습니다 . 여러 작업에서 사용할 수있는 구성 파일의 실제 목록이 필요한 경우를 사용하여 명시 적으로 만들어야합니다 list(configfiles).


0

이 명령 rglob은 디렉토리 구조의 가장 깊은 하위 수준에서 무한 재귀를 수행합니다. 한 수준 만 원하는 경우에는 사용하지 마십시오.

OP가 glob.glob 사용에 대해 이야기하고 있다는 것을 알고 있습니다. 그러나 이것이 모든 하위 폴더를 재귀 적으로 검색하려는 의도에 대한 답이라고 생각합니다.

rglob함수는 최근 데이터 읽기 순서에 대한 고정 된 가정으로 폴더 구조를 사용하는 데이터 처리 알고리즘의 속도를 100 배 향상 시켰습니다. 그러나 rglob우리는 지정된 상위 디렉토리 또는 그 아래의 모든 파일을 한 번만 스캔하고 이름을 목록 (백만 개 이상의 파일)에 저장 한 다음 해당 목록을 사용하여 어느 위치에서든 열어야하는 파일을 결정할 수있었습니다. 파일 이름 지정 규칙만을 기반으로 한 미래와 그들이 어느 폴더에 있었는지.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.