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.