Python'da bir dosya bul


Yanıtlar:


251

os.walk cevaptır, bu ilk eşleşmeyi bulacaktır:

import os

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

Ve bu, tüm eşleşmeleri bulacaktır:

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

Ve bu bir kalıpla eşleşecek:

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
Bu örneklerin yalnızca dosyaları bulacağını, aynı ada sahip dizinleri bulamayacağını unutmayın. if name in file or name in dirs
Mark E. Hamilton

9
Büyük / küçük harf duyarlılığına dikkat edin. for name in files:arayan başarısız olur super-photo.jpgo geldiğinde super-photo.JPGdosya sisteminde. (hayatımın bir saatini geri istiyorum ;-) Biraz dağınık bir düzeltmeif str.lower(name) in [x.lower() for x in files]
matt wilkie

Sonuç listesini hazırlamak yerine getiri kullanmaya ne dersiniz ? ..... eğer fnmatch.fnmatch (ad, desen): verim os.path.join (kök, ad)
Berci

Lütfen yanıtınızı Python 3.x ilkellerine güncellemeyi düşünün
Dima Tisnek

1
Kavrama listesi fonksiyonun yerini alabilir, örneğin find_all: res = [os.path.join (root, name) for root, dirs, files in os.walk (path) if name in files]
Nir

23

Daha os.walkbüyük bir dizinin bir sürümünü kullandım ve 3.5 saniye civarında süreler aldım. Büyük bir gelişme olmadan iki rastgele çözüm denedim, sonra şimdi yaptım:

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

Yalnızca POSIX olsa da 0.25 saniyem var.

Buradan, tüm aramayı platformdan bağımsız bir şekilde optimize etmenin tamamen mümkün olduğuna inanıyorum, ancak araştırmayı burada durdurdum.


6

Ubuntu üzerinde Python kullanıyorsanız ve sadece Ubuntu üzerinde çalışmasını istiyorsanız, çok daha hızlı bir yol, terminalin locateprogramını bu şekilde kullanmaktır .

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, listmutlak dosya yollarının. Bu, yukarıdaki yöntemlerden 10.000 kat daha hızlı ve yaptığım bir arama için ~ 72.000 kat daha hızlıydı.


5

Python 3.4 veya daha yenisinde, özyinelemeli genelleme yapmak için pathlib'i kullanabilirsiniz:

>>> 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')]

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

Python 3.5 veya daha yeni sürümlerde, aşağıdaki gibi yinelemeli genelleme de yapabilirsiniz:

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

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



3

Python 2 ile çalışıyorsanız, kendine atıfta bulunan sembolik bağların neden olduğu pencerelerde sonsuz özyineleme ile ilgili bir sorununuz var.

Bu komut dosyası, bunları takip etmekten kaçınacaktır. Bunun pencerelere özgü olduğunu unutmayın !

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

Dosya adları listesindeki dosyalara işaret eden tüm yolları içeren bir liste döndürür. Kullanım:

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

2

Aşağıda, ilk eşleşme ve tüm eşleşmeler arasında geçiş yapmak için bir boole "ilk" bağımsız değişkeni kullanıyoruz (". -Adı dosyası bul" ile eşdeğer bir varsayılan):

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

Cevap, mevcut olanlara çok benzer, ancak biraz optimize edilmiştir.

Böylece herhangi bir dosya veya klasörü kalıba göre bulabilirsiniz:

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)
    )

alt dize ile:

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
    )

veya bir yüklem kullanarak:

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)
    )

yalnızca dosyaları veya yalnızca klasörleri aramak için - örneğin, neye ihtiyacınız olduğuna bağlı olarak "dirs + files" yerine yalnızca "dirs" veya yalnızca "files" yazın.

Saygılarımızla.


0

SARose'un cevabı, Ubuntu 20.04 LTS'den güncelleme yapana kadar benim için çalıştı. Kodunda yaptığım küçük değişiklik, onu en son Ubuntu sürümünde çalışmasını sağlıyor.

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.