在python中查找文件


Answers:


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.jpg时将失败super-photo.JPG。(我一小时的时间if str.lower(name) in [x.lower() for x in files]
都想

如何使用yield而不是准备结果列表?..... if fnmatch.fnmatch(name,pattern):yield os.path.join(root,name)
Berci 2015年

请考虑更新对Python 3.x原语的答案
Dima Tisnek '16

1
理解中列表可以替换的功能,例如find_all:RES = [os.path.join(根,名称),用于在os.walk(路径)根,显示目录,文件,如果名字文件]
尼尔

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_resultslist绝对文件路径中的一个。这比上述方法快10,000倍,而我做过一次搜索,快了约72,000倍。


5

在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或更高版本中,您还可以像这样进行递归glob:

>>> 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上的无限递归问题。

该脚本将避免遵循这些规则。请注意,这是特定于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文件”):

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.