अजगर में एक फ़ाइल खोजें


110

मेरे पास एक फ़ाइल है जो प्रत्येक उपयोगकर्ता की मशीन पर एक अलग स्थान पर हो सकती है। क्या फ़ाइल की खोज को लागू करने का कोई तरीका है? ऐसा तरीका जिससे मैं खोज करने के लिए फ़ाइल का नाम और निर्देशिका ट्री पास कर सकूं?


देखें ओएस मॉड्यूल 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
— Mark E. Hamilton

9
केस सेंसिटिविटी से सावधान रहें। यह फ़ाइल सिस्टम में कब है, यह देखने में for name in files:विफल रहेगा । (मेरे जीवन का एक घंटा मैं वापस चाहूंगा; ;-) कुछ गन्दा तय हैsuper-photo.jpgsuper-photo.JPGif str.lower(name) in [x.lower() for x in files]
— मैट विल्की

परिणाम सूची तैयार करने के बजाय उपज का उपयोग करने के बारे में क्या ? ..... अगर fnmatch.fnmatch (नाम, पैटर्न): उपज os.path.join (रूट, नाम)
— Berci

कृपया अपने उत्तर को पायथन 3.x प्राइमेटिव्स के लिए अपडेट करने पर विचार करें
— Dima Tisnek

1
समझ की सूची फ़ंक्शन को प्रतिस्थापित कर सकती है, उदाहरण के लिए find_all: res = [os.path.join (रूट, नाम) रूट, डायर, फ़ाइलों के लिए os.walk (पथ) यदि फ़ाइलों में नाम]
— Nir

23

मैंने एक संस्करण का उपयोग किया os.walkऔर एक बड़ी निर्देशिका पर लगभग 3.5 सेकंड का समय मिला। मैंने बिना किसी महान सुधार के दो यादृच्छिक समाधानों की कोशिश की, फिर बस:

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

जबकि यह POSIX-only है, मुझे 0.25 सेकंड मिला है।

इससे, मेरा मानना ​​है कि पूरी तरह से एक प्लेटफॉर्म-स्वतंत्र तरीके से पूरी खोज को अनुकूलित करना संभव है, लेकिन यह वह जगह है जहां मैंने शोध को रोक दिया है।


6

यदि आप उबंटू पर पायथन का उपयोग कर रहे हैं और आप केवल उबंटू पर काम करना चाहते हैं 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 गुना अधिक तेज है और एक खोज के लिए मैंने इसे ~ 72,000 गुना तेज किया।


5

पायथन 3.4 या नए में आप पुनरावर्ती ग्लोबिंग करने के लिए पैथलिब का उपयोग कर सकते हैं:

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

पायथन 3.5 या नए में आप इस तरह से पुनरावर्ती ग्लोबिंग भी कर सकते हैं:

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

संदर्भ: https://docs.python.org/3/library/glob.html#glob.glob


3

तेजी से, ओएस-स्वतंत्र खोज के लिए, उपयोग करें scandir

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

विवरण के लिए http://bugs.python.org/issue11406 पढ़ें ।


7
विशेष रूप से, scandir.walk()@ नादिया के उत्तर के अनुसार उपयोग करें । ध्यान दें कि यदि आप पायथन 3.5+ का उपयोग कर रहे हैं, os.walk()तो scandir.walk()पहले से ही स्पीडअप है। इसके अलावा, PEP 471 संभवतः उस मुद्दे की जानकारी के लिए पढ़ने के लिए एक बेहतर दस्तावेज़ है।
— बेन होयट

3

यदि आप पायथन 2 के साथ काम कर रहे हैं, तो आपको स्वयं-संदर्भित सिम्बलिंक के कारण खिड़कियों पर अनंत पुनरावृत्ति की समस्या है।

यह स्क्रिप्ट उन लोगों का अनुसरण करने से बचेंगी। ध्यान दें कि यह विंडोज़-विशिष्ट है !

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

नीचे हम पहले मैच और सभी मैचों के बीच स्विच करने के लिए एक बूलियन "पहले" तर्क का उपयोग करते हैं (एक डिफ़ॉल्ट जो "खोज -नाम फ़ाइल" के बराबर है):।

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 से अपडेट नहीं हो जाता। मैंने उनके कोड में जो थोड़ा सा बदलाव किया, वह नवीनतम उबंटू रिलीज पर काम करता है।

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.