디렉토리에서 필터링 된 파일 목록 가져 오기


281

Python을 사용하여 디렉토리에 파일 목록을 가져 오려고하지만 모든 파일 목록을 원하지 않습니다.

내가 본질적으로 원하는 것은 다음과 같지만 파이썬을 사용하고 ls를 실행하지 않는 기능을 수행하는 능력입니다.

ls 145592*.jpg

내장 된 방법이 없다면 현재 for 루프를 작성하여 결과를 반복 os.listdir()하고 일치하는 모든 파일을 새 목록에 추가하려고합니다.

그러나 해당 디렉토리에는 많은 파일이 있으므로 더 효율적인 방법 (또는 내장 방법)이 있기를 바랍니다.


[이 링크는 당신에게 도움이 될 것입니다 :) 디렉토리에서 필터링 된 파일 목록 가져 오기 ] ( codereview.stackexchange.com/a/33642 )
sha111

응용 프로그램에 중요한 경우 정렬 순서에 특별한주의를 기울일 수 있습니다.
lumbric

답변:


385

21
방금 파이썬 문서에서 glob ()가 "서브 쉘을 호출하는 것이 아니라 os.listdir () 및 fnmatch.fnmatch () 함수를 사용하여 수행됨"을 알았습니다. 다시 말해서, glob ()에는 기대할 수있는 효율성 향상이 없습니다.
Ben Hoyt

5
한 가지 주요 차이점이 있습니다. glob.glob('145592*.jpg')파일의 전체 절대 경로를 ls 145592*.jpg인쇄하고 파일 목록 만 인쇄합니다.
Ébe Isaac

8
@Ben 서브 쉘 (서브 프로세스)을 호출하면 효율성이 향상되는 이유는 무엇입니까?
Paulo Neves

7
@PauloNeves : 사실, 위의 의견은 7 년 후에 나에게 의미가 없습니다. :-) glob()와일드 카드 필터링을 수행하기 위해 특수 운영 체제 호출 대신 listdir + fnmatch 만 사용 한다는 사실을 언급하고 있다고 생각 합니다. 예를 들어, Windows에서 FindFirstFileAPI를 사용하면 와일드 카드를 지정하여 OS에서 필터링을 직접 수행하고 더 효율적으로 수행 할 수 있습니다 (Linux에서는 이에 상응하는 것으로 생각하지 않습니다).
벤 Hoyt

1
@marsh : 항상 그렇듯이 프로세스의 현재 작업 디렉토리.
Ignacio Vazquez-Abrams

125

glob.glob()(Ignacio에 따라) 확실히하는 방법입니다. 그러나 더 복잡한 일치가 필요한 경우 목록 이해 및 re.match()로 다음과 같이 할 수 있습니다.

files = [f for f in os.listdir('.') if re.match(r'[0-9]+.*\.jpg', f)]

보다 유연하지만, 효율적이지 않습니다.


이것은 확실히 더 강력한 것 같습니다. 예를 들어 다음과 같은 작업을 수행해야합니다.[0-9]+
demongolem

3
예, 확실히 더 강력합니다. 그러나 fnmatch는 [0123456789]시퀀스를 지원하고 ( docs 참조 ) fnmatch.filter()이 루프를 약간 더 효율적으로 만드는 기능 도 있습니다 .
Ben Hoyt

49

간단하게 유지하십시오.

import os
relevant_path = "[path to folder]"
included_extensions = ['jpg','jpeg', 'bmp', 'png', 'gif']
file_names = [fn for fn in os.listdir(relevant_path)
              if any(fn.endswith(ext) for ext in included_extensions)]

영어로 잘 읽히기 때문에 이런 형태의 목록 이해를 선호합니다.

네 번째 줄은 다음과 같이 읽습니다. 내 경로에 대해 os.listdir의 각 fn에 대해 포함 된 확장 중 하나와 일치하는 것을 제공하십시오.

초보자 파이썬 프로그래머는 필터링에 목록 이해를 사용하는 데 실제로 익숙하지 않을 수 있으며 매우 큰 데이터 세트에 대해 약간의 메모리 오버 헤드가있을 수 있지만 디렉토리 및 기타 간단한 문자열 필터링 작업을 나열하는 경우 목록 이해가 더 깨끗합니다. 문서화 가능한 코드.

이 디자인의 유일한 점은 목록 대신 문자열을 전달하는 실수를 방지하는 것입니다. 예를 들어 실수로 문자열을 목록으로 변환하고 문자열의 모든 문자를 검사하면 잘못된 긍정 오류가 발생할 수 있습니다.

그러나 이해하기 어려운 솔루션보다 수정하기 쉬운 문제가있는 것이 좋습니다.


5
일련 의 엔딩 이 필요하기 any()때문에 여기에 필요한 것은 없습니다 . 충분합니다. str.endswith()if fn.endswith(included_extentensions)
Martijn Pieters

3
str.endswith(seq)Martijn이 지적한 것을 사용하지 않는 비 효율성 외에도 파일이 .ext확장명을 갖기 위해 끝나야하기 때문에 이것은 정확하지 않습니다 . 이 코드는 예를 들어 "myjpg"라는 파일이나 "png"라는 디렉토리를 찾습니다. 해결하려면, 그냥 각 확장 앞에 included_extensionsA를을 ..
벤 Hoyt

나는 분명히 실행되지 않았거나 실행할 수없는 답변에 항상 코드를 조심합니다. 변수 included_extensionsincluded_extentsions? 그렇지 않으면 이것이 내가 선호하는 답변이므로 유감입니다.
Auspice


17

glob모듈이있는 필터 :

글로브 가져 오기

import glob

와일드 카드 :

files=glob.glob("data/*")
print(files)

Out:

['data/ks_10000_0', 'data/ks_1000_0', 'data/ks_100_0', 'data/ks_100_1',
'data/ks_100_2', 'data/ks_106_0', 'data/ks_19_0', 'data/ks_200_0', 'data/ks_200_1', 
'data/ks_300_0', 'data/ks_30_0', 'data/ks_400_0', 'data/ks_40_0', 'data/ks_45_0', 
'data/ks_4_0', 'data/ks_500_0', 'data/ks_50_0', 'data/ks_50_1', 'data/ks_60_0', 
'data/ks_82_0', 'data/ks_lecture_dp_1', 'data/ks_lecture_dp_2']

Fiter 확장 .txt:

files = glob.glob("/home/ach/*/*.txt")

단일 문자

glob.glob("/home/ach/file?.txt")

숫자 범위

glob.glob("/home/ach/*[0-9]*")

알파벳 범위

glob.glob("/home/ach/[a-c]*")

12

예비 코드

import glob
import fnmatch
import pathlib
import os

pattern = '*.py'
path = '.'

해결 방법 1- "글로브"사용

# lookup in current dir
glob.glob(pattern)

In [2]: glob.glob(pattern)
Out[2]: ['wsgi.py', 'manage.py', 'tasks.py']

해결 방법 2- "os"+ "fnmatch"사용

변형 2.1- 현재 디렉토리의 조회

# lookup in current dir
fnmatch.filter(os.listdir(path), pattern)

In [3]: fnmatch.filter(os.listdir(path), pattern)
Out[3]: ['wsgi.py', 'manage.py', 'tasks.py']

변형 2.2- 조회 재귀

# lookup recursive
for dirpath, dirnames, filenames in os.walk(path):

    if not filenames:
        continue

    pythonic_files = fnmatch.filter(filenames, pattern)
    if pythonic_files:
        for file in pythonic_files:
            print('{}/{}'.format(dirpath, file))

결과

./wsgi.py
./manage.py
./tasks.py
./temp/temp.py
./apps/diaries/urls.py
./apps/diaries/signals.py
./apps/diaries/actions.py
./apps/diaries/querysets.py
./apps/library/tests/test_forms.py
./apps/library/migrations/0001_initial.py
./apps/polls/views.py
./apps/polls/formsets.py
./apps/polls/reports.py
./apps/polls/admin.py

해결 방법 3- "pathlib"사용

# lookup in current dir
path_ = pathlib.Path('.')
tuple(path_.glob(pattern))

# lookup recursive
tuple(path_.rglob(pattern))

노트:

  1. 파이썬 3.4에서 테스트
  2. "pathlib"모듈은 Python 3.4에서만 추가되었습니다
  3. Python 3.5에는 glob.glob https://docs.python.org/3.5/library/glob.html#glob.glob 를 사용한 재귀 조회 기능이 추가되었습니다 . 내 컴퓨터는 Python 3.4와 함께 설치되었으므로 테스트하지 않았습니다.

9

os.walk를 사용하여 파일을 재귀 적으로 나열하십시오.

import os
root = "/home"
pattern = "145992"
alist_filter = ['jpg','bmp','png','gif'] 
path=os.path.join(root,"mydir_to_scan")
for r,d,f in os.walk(path):
    for file in f:
        if file[-3:] in alist_filter and pattern in file:
            print os.path.join(root,file)

슬라이스 할 필요가 없습니다. file.endswith(alist_filter)충분하다.
Martijn Pieters

5
import os

dir="/path/to/dir"
[x[0]+"/"+f for x in os.walk(dir) for f in x[2] if f.endswith(".jpg")]

전체 경로가 포함 된 jpg 파일 목록이 표시됩니다. 당신은 대체 할 수 x[0]+"/"+ff단지 파일 이름을. f.endswith(".jpg")원하는 문자열 조건으로 바꿀 수도 있습니다 .


3

더 높은 수준의 접근 방식을 원할 수도 있습니다 (findtools 로 구현하고 패키지했습니다 ).

from findtools.find_files import (find_files, Match)


# Recursively find all *.txt files in **/home/**
txt_files_pattern = Match(filetype='f', name='*.txt')
found_files = find_files(path='/home', match=txt_files_pattern)

for found_file in found_files:
    print found_file

함께 설치할 수 있습니다

pip install findtools

2

"path / to / images"에 "jpg"및 "png"확장자를 가진 파일 이름 :

import os
accepted_extensions = ["jpg", "png"]
filenames = [fn for fn in os.listdir("path/to/images") if fn.split(".")[-1] in accepted_extensions]

이것은 @ ramsey0
chb

1

Python 표준 라이브러리 3.4 이상에서 사용 가능한 pathlib 를 사용할 수 있습니다 .

from pathlib import Path

files = [f for f in Path.cwd().iterdir() if f.match("145592*.jpg")]

1

패턴을 정의하고 확인할 수 있습니다. 여기에서 시작과 끝 패턴을 모두 가져 와서 파일 이름에서 찾습니다. 파일에는 디렉토리의 모든 파일 목록이 포함됩니다.

import os
PATTERN_START = "145592"
PATTERN_END = ".jpg"
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
for r,d,FILES in os.walk(CURRENT_DIR):
    for FILE in FILES:
        if PATTERN_START in FILE and PATTERN_END in FILE:
            print FILE

0

str.split ()은 어떻습니까? 가져올 것이 없습니다.

import os

image_names = [f for f in os.listdir(path) if len(f.split('.jpg')) == 2]

2
이것은 @gypsy의
Sushanth

이것은 @ ramsey0의 답변을 사용하는 것과 비슷 f.endswith('.jpg')하지만 (도 선택합니다 filename.jpg.ext)
anjsimmo

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