it-swarm-ja.tech

pythonでファイルを見つけます

各ユーザーのマシンの異なる場所にあるファイルがあります。ファイルの検索を実装する方法はありますか?検索するファイルの名前とディレクトリツリーを渡す方法は?

86
directedition

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')
199
Nadia Alramli

os.walkのバージョンを使用しましたが、より大きなディレクトリでは約3.5秒かかりました。私は2つのランダムな解決策を試してみましたが、大きな改善はありませんでした。

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

POSIXのみですが、0.25秒を取得しました。

このことから、プラットフォームに依存しない方法で検索全体を最適化することは完全に可能だと思いますが、ここで研究を中止しました。

19
kgadek

OSに依存しない高速検索を行うには、scandirを使用します

https://github.com/benhoyt/scandir/#readme

理由の詳細については、 http://bugs.python.org/issue11406 をお読みください。

3
Dima Tisnek

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_resultsは、絶対ファイルパスのlistです。これは上記の方法よりも10,000倍高速であり、1回の検索で最大72,000倍高速でした。

3
SARose

Python 2を使用している場合、自己参照シンボリックリンクが原因で、ウィンドウで無限再帰が発生する問題があります。

このスクリプトはそれらに従うことを避けます。これはwindows-specific!であることに注意してください。

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"])
3
F.M.F.

Python 3.4以降では、pathlibを使用して再帰的なグロビングを実行できます。

>>> 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以降では、次のように再帰的なグロビングを行うこともできます。

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

リファレンス: https://docs.python.org/3/library/glob.html#glob.glob

2
Kenyon

以下では、ブール値の「最初の」引数を使用して、最初の一致とすべての一致を切り替えます(デフォルトは「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 
1
Leon Chang

Os.walkまたはos.listdirについては os module をご覧ください

サンプルコードについては、この質問も参照してください 下のディレクトリを掘らないでos.walk

0
Martin Beckett