파이썬에서 파일 찾기


110

각 사용자 컴퓨터의 다른 위치에있을 수있는 파일이 있습니다. 파일 검색을 구현하는 방법이 있습니까? 검색 할 파일 이름과 디렉토리 트리를 전달할 수있는 방법은 무엇입니까?


참고 항목 os 모듈을 os.walk 또는 참조이 질문 os.listdir stackoverflow.com/questions/229186/... 샘플 코드
마틴 베켓

답변:


251

os.walk 가 정답이며 첫 번째 일치 항목을 찾습니다.

import os

def find(name, path):
    for root, dirs, files in os.walk(path):
        if name in files:
            return os.path.join(root, name)

그리고 이것은 모든 일치를 찾을 것입니다 :

def find_all(name, path):
    result = []
    for root, dirs, files in os.walk(path):
        if name in files:
            result.append(os.path.join(root, name))
    return result

그리고 이것은 패턴과 일치합니다.

import os, fnmatch
def find(pattern, path):
    result = []
    for root, dirs, files in os.walk(path):
        for name in files:
            if fnmatch.fnmatch(name, pattern):
                result.append(os.path.join(root, name))
    return result

find('*.txt', '/path/to/dir')

2
이 예제는 이름이 같은 디렉토리가 아닌 파일 만 찾습니다. 당신이 찾으려면 어떤 그 이름을 가진 디렉토리 오브젝트를 사용하면 사용 할 수 있습니다if name in file or name in dirs
마크 E. 해밀턴에게

9
대소 문자 구분에주의하십시오. 파일 시스템에있는 경우 검색에 for name in files:실패 합니다. (내 인생의 시간은 내가 다시하고 싶은 ;-) 다소 지저분한 수정이super-photo.jpgsuper-photo.JPGif str.lower(name) in [x.lower() for x in files]
매트 윌키는

결과 목록을 준비하는 대신 yield 를 사용하는 것은 어떻습니까? ..... if fnmatch.fnmatch (name, pattern) : yield os.path.join (root, name)
Berci

파이썬 3.x를 프리미티브에 대한 답을 업데이트 해 주시기 바랍니다
디마 Tisnek에게

1
Comprehention list can replace the function, eg find_all : res = [os.path.join (root, name) for root, dirs, files in os.walk (path) if name in files]
Nir

23

나는 버전을 사용하고 os.walk더 큰 디렉토리에서 약 3.5 초를 얻었습니다. 크게 개선되지 않은 두 가지 무작위 솔루션을 시도한 다음 방금 수행했습니다.

paths = [line[2:] for line in subprocess.check_output("find . -iname '*.txt'", shell=True).splitlines()]

POSIX 전용이지만 0.25 초를 얻었습니다.

이로부터 플랫폼 독립적 인 방식으로 전체 검색을 최적화하는 것이 전적으로 가능하다고 생각하지만 여기서 연구를 중단했습니다.


6

Ubuntu에서 Python을 사용하고 Ubuntu에서만 작동하도록하려면 터미널 locate프로그램을 이와 같이 사용하는 것이 훨씬 더 빠른 방법입니다 .

import subprocess

def find_files(file_name):
    command = ['locate', file_name]

    output = subprocess.Popen(command, stdout=subprocess.PIPE).communicate()[0]
    output = output.decode()

    search_results = output.split('\n')

    return search_results

search_resultsA는 list절대 파일 경로가. 이것은 위의 방법보다 10,000 배 더 빠르며 한 번의 검색에 대해 ~ 72,000 배 더 빠릅니다.


5

Python 3.4 이상에서는 pathlib를 사용하여 재귀 적 globbing을 수행 할 수 있습니다.

>>> import pathlib
>>> sorted(pathlib.Path('.').glob('**/*.py'))
[PosixPath('build/lib/pathlib.py'),
 PosixPath('docs/conf.py'),
 PosixPath('pathlib.py'),
 PosixPath('setup.py'),
 PosixPath('test_pathlib.py')]

참조 : https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob

Python 3.5 이상에서는 다음과 같이 재귀 적 globbing을 수행 할 수도 있습니다.

>>> import glob
>>> glob.glob('**/*.txt', recursive=True)
['2.txt', 'sub/3.txt']

참조 : https://docs.python.org/3/library/glob.html#glob.glob



3

Python 2로 작업하는 경우 자체 참조 심볼릭 링크로 인해 창에서 무한 재귀 문제가 발생합니다.

이 스크립트는 그것들을 따르지 않을 것입니다. 이것은 Windows 전용입니다 !

import os
from scandir import scandir
import ctypes

def is_sym_link(path):
    # http://stackoverflow.com/a/35915819
    FILE_ATTRIBUTE_REPARSE_POINT = 0x0400
    return os.path.isdir(path) and (ctypes.windll.kernel32.GetFileAttributesW(unicode(path)) & FILE_ATTRIBUTE_REPARSE_POINT)

def find(base, filenames):
    hits = []

    def find_in_dir_subdir(direc):
        content = scandir(direc)
        for entry in content:
            if entry.name in filenames:
                hits.append(os.path.join(direc, entry.name))

            elif entry.is_dir() and not is_sym_link(os.path.join(direc, entry.name)):
                try:
                    find_in_dir_subdir(os.path.join(direc, entry.name))
                except UnicodeDecodeError:
                    print "Could not resolve " + os.path.join(direc, entry.name)
                    continue

    if not os.path.exists(base):
        return
    else:
        find_in_dir_subdir(base)

    return hits

파일 이름 목록에있는 파일을 가리키는 모든 경로가있는 목록을 반환합니다. 용법:

find("C:\\", ["file1.abc", "file2.abc", "file3.abc", "file4.abc", "file5.abc"])

2

아래에서는 부울 "first"인수를 사용하여 첫 번째 일치 항목과 모든 일치 항목 사이를 전환합니다 (기본값은 "find. -name file"과 동일 함).

import  os

def find(root, file, first=False):
    for d, subD, f in os.walk(root):
        if file in f:
            print("{0} : {1}".format(file, d))
            if first == True:
                break 

0

대답은 기존의 것과 매우 유사하지만 약간 최적화되었습니다.

따라서 패턴별로 모든 파일 또는 폴더를 찾을 수 있습니다.

def iter_all(pattern, path):
    return (
        os.path.join(root, entry)
        for root, dirs, files in os.walk(path)
        for entry in dirs + files
        if pattern.match(entry)
    )

하위 문자열로 :

def iter_all(substring, path):
    return (
        os.path.join(root, entry)
        for root, dirs, files in os.walk(path)
        for entry in dirs + files
        if substring in entry
    )

또는 술어 사용 :

def iter_all(predicate, path):
    return (
        os.path.join(root, entry)
        for root, dirs, files in os.walk(path)
        for entry in dirs + files
        if predicate(entry)
    )

파일 만 검색하거나 폴더 만 검색하려면- "dirs + files"를 필요에 따라 "dirs"또는 "files"로만 바꿉니다.

문안 인사.


0

SARose의 답변은 Ubuntu 20.04 LTS에서 업데이트 할 때까지 저에게 효과적이었습니다. 그의 코드를 약간 변경하여 최신 Ubuntu 릴리스에서 작동합니다.

import subprocess

def find_files(file_name):
    file_name = 'chromedriver'
    command = ['locate'+ ' ' + file_name]
    output = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()[0]
    output = output.decode()
    search_results = output.split('\n')
    return search_results
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.