निर्देशिका में फ़ाइलों की फ़िल्टर की गई सूची प्राप्त करें


281

मैं पायथन का उपयोग करके एक निर्देशिका में फ़ाइलों की एक सूची प्राप्त करने की कोशिश कर रहा हूं, लेकिन मुझे सभी फ़ाइलों की सूची नहीं चाहिए।

जो मैं अनिवार्य रूप से चाहता हूं वह निम्नलिखित की तरह कुछ करने की क्षमता है लेकिन पायथन का उपयोग करना और एलएस निष्पादित नहीं करना है।

ls 145592*.jpg

यदि इसके लिए कोई अंतर्निहित पद्धति नहीं है, तो मैं वर्तमान में ए के परिणामों के माध्यम से लूप के लिए लिखने की सोच रहा हूं os.listdir() और सभी मिलान फ़ाइलों को एक नई सूची में संलग्न करने के ।

हालांकि, उस निर्देशिका में बहुत सारी फाइलें हैं और इसलिए मैं उम्मीद कर रहा हूं कि एक अधिक कुशल विधि (या एक अंतर्निहित विधि) है।


[यह लिंक आपकी मदद कर सकता है :) एक निर्देशिका में फ़ाइलों की एक फ़िल्टर्ड सूची प्राप्त करें] ( codereview.stackexchange.com/a/33642 )
sha111

ध्यान दें कि आप क्रमांकन के बारे में विशेष ध्यान रख सकते हैं यदि यह आपके आवेदन के लिए महत्वपूर्ण है।
लम्बरी

जवाबों:


385

21
ओह, मैंने अभी देखा कि पायथन डॉक्स कहते हैं ग्लोब () "कॉन्सर्ट में os.listdir () और fnmatch.fnmatch () फंक्शंस का उपयोग करके किया जाता है, न कि वास्तव में सब-इनक्लूड करके"। दूसरे शब्दों में, ग्लोब () में दक्षता में सुधार नहीं हो सकता है जिसकी कोई अपेक्षा कर सकता है।
बेन होयट

5
एक मुख्य अंतर है: glob.glob('145592*.jpg')फाइलों के पूरे निरपेक्ष पथ को ls 145592*.jpgप्रिंट करता है जबकि केवल फाइलों की सूची को प्रिंट करता है।
12be इसहाक

8
@ क्यों एक सबमिशन (सबप्रोसेस) लागू करने से कोई दक्षता में सुधार होगा?
पाउलो नेव्स

7
@PauloNeves: सच, ऊपर मेरी टिप्पणी मेरे लिए 7 साल बाद भी कोई मतलब नहीं है। :-) मुझे लगता है कि मैं इस तथ्य का उल्लेख कर रहा था कि glob()वाइल्डकार्ड फ़िल्टरिंग करने के लिए विशेष ऑपरेटिंग सिस्टम कॉल के बजाय बस listdir + fnmatch का उपयोग करता है। उदाहरण के लिए, विंडोज पर FindFirstFileएपीआई आपको वाइल्डकार्ड निर्दिष्ट करने की अनुमति देता है, इसलिए ओएस सीधे फ़िल्टरिंग करता है, और संभवतः अधिक कुशलता से (मुझे नहीं लगता कि लिनक्स पर एक बराबर है)।
बेन होयट

1
@ मार्श: हमेशा की तरह, प्रक्रिया की वर्तमान कार्यशील निर्देशिका।
इग्नासियो वाज़क्वेज़-अब्राम्स

124

glob.glob()निश्चित रूप से इसे करने का तरीका है (इग्नासियो के अनुसार)। हालाँकि, यदि आपको अधिक जटिल मिलान की आवश्यकता है, तो आप इसे सूची समझ और re.match()कुछ इस तरह से कर सकते हैं:

files = [f for f in os.listdir('.') if re.match(r'[0-9]+.*\.jpg', f)]

अधिक लचीला, लेकिन जैसा कि आप ध्यान दें, कम कुशल।


यह निश्चित रूप से अधिक शक्तिशाली प्रतीत होता है। उदाहरण के लिए, कुछ करने के लिए जैसे[0-9]+
demongolem

3
हां, निश्चित रूप से अधिक शक्तिशाली - हालांकि fnmatch [0123456789]दृश्यों का समर्थन करता है ( डॉक्स देखें ), और इसमें fnmatch.filter()फ़ंक्शन भी है जो इस लूप को थोड़ा अधिक कुशल बनाता है।
बेन होयट

49

इसे सरल रखें:

import os
relevant_path = "[path to folder]"
included_extensions = ['jpg','jpeg', 'bmp', 'png', 'gif']
file_names = [fn for fn in os.listdir(relevant_path)
              if any(fn.endswith(ext) for ext in included_extensions)]

मैं सूची बोध के इस रूप को पसंद करता हूं क्योंकि यह अंग्रेजी में अच्छी तरह से पढ़ता है।

मैं चौथी पंक्ति को इस प्रकार पढ़ता हूं: मेरे पथ के लिए os.listdir में प्रत्येक fn के लिए, मुझे केवल वही दें जो मेरे शामिल एक्सटेंशन में से किसी एक से मेल खाता हो।

यह नौसिखिया अजगर प्रोग्रामर्स के लिए मुश्किल हो सकता है कि वे फ़िल्टरिंग के लिए सूची समझ का उपयोग करने के लिए अभ्यस्त हों, और इसमें बहुत बड़े डेटा सेट के लिए कुछ मेमोरी ओवरहेड हो सकते हैं, लेकिन एक निर्देशिका और अन्य सरल स्ट्रिंग फ़िल्टरिंग कार्यों को सूचीबद्ध करने के लिए, सूची की आशंका अधिक साफ होती है। दस्तावेजी कोड।

इस डिज़ाइन की एकमात्र बात यह है कि यह आपको सूची के बजाय स्ट्रिंग पास करने की गलती करने से बचाता नहीं है। उदाहरण के लिए यदि आप गलती से एक स्ट्रिंग को एक सूची में परिवर्तित करते हैं और एक स्ट्रिंग के सभी पात्रों के खिलाफ जांच समाप्त करते हैं, तो आप गलत सकारात्मकता का एक समूह प्राप्त कर सकते हैं।

लेकिन एक समस्या को हल करना बेहतर है जो एक समाधान की तुलना में ठीक करना आसान है जिसे समझना मुश्किल है।


5
ऐसा नहीं है कि यहां कोई जरूरत नहीं है any(), क्योंकि अंत का str.endswith()एक क्रम लेता है । if fn.endswith(included_extentensions)पर्याप्त से अधिक है।
मार्टिन पीटर्स

3
str.endswith(seq)उस मार्टिज़न का उपयोग न करने की अक्षमता के अलावा , यह सही नहीं है, क्योंकि .extउस एक्सटेंशन के लिए एक फ़ाइल को इसके साथ समाप्त होना है। यह कोड (उदाहरण के लिए) "myjpg" नामक एक फ़ाइल या "पीएनजी" नाम की एक निर्देशिका भी मिलेगा। ठीक करने के लिए, बस included_extensionsएक के साथ प्रत्येक विस्तार उपसर्ग .
बेन होयट

मैं हमेशा जवाबों में कोड से थोड़ा सावधान रहता हूं जो जाहिर तौर पर चलाया नहीं गया है या नहीं चल सकता है। चर included_extensionsबनाम included_extentsions? अफ़सोस क्योंकि अन्यथा यह मेरा पसंदीदा उत्तर है।
शुभ अंक

39

एक अन्य विकल्प:

>>> import os, fnmatch
>>> fnmatch.filter(os.listdir('.'), '*.py')
['manage.py']

https://docs.python.org/3/library/fnmatch.html


5
ठीक यही globएक लाइन पर होता है।
इते ग्रामदेव

केवल अंतर केवल फ़ाइल नाम वापस globकरने के विपरीत पूर्ण पथ देता है os.listdir। कम से कम यह पायथन 2 में क्या हो रहा है
कार्तिक रघुपति

17

globमॉड्यूल के साथ फ़िल्टर करें :

आयात ग्लोब

import glob

वाइल्ड कार्ड:

files=glob.glob("data/*")
print(files)

Out:

['data/ks_10000_0', 'data/ks_1000_0', 'data/ks_100_0', 'data/ks_100_1',
'data/ks_100_2', 'data/ks_106_0', 'data/ks_19_0', 'data/ks_200_0', 'data/ks_200_1', 
'data/ks_300_0', 'data/ks_30_0', 'data/ks_400_0', 'data/ks_40_0', 'data/ks_45_0', 
'data/ks_4_0', 'data/ks_500_0', 'data/ks_50_0', 'data/ks_50_1', 'data/ks_60_0', 
'data/ks_82_0', 'data/ks_lecture_dp_1', 'data/ks_lecture_dp_2']

लेखक एक्सटेंशन .txt:

files = glob.glob("/home/ach/*/*.txt")

एक एकल चरित्र

glob.glob("/home/ach/file?.txt")

नंबर की रेंज

glob.glob("/home/ach/*[0-9]*")

वर्णमाला के रंग

glob.glob("/home/ach/[a-c]*")

12

प्रारंभिक कोड

import glob
import fnmatch
import pathlib
import os

pattern = '*.py'
path = '.'

समाधान 1 - "ग्लोब" का उपयोग करें

# lookup in current dir
glob.glob(pattern)

In [2]: glob.glob(pattern)
Out[2]: ['wsgi.py', 'manage.py', 'tasks.py']

समाधान २ - "os" + "fnmatch" का उपयोग करें

वेरिएंट 2.1 - वर्तमान डायर में लुकअप

# lookup in current dir
fnmatch.filter(os.listdir(path), pattern)

In [3]: fnmatch.filter(os.listdir(path), pattern)
Out[3]: ['wsgi.py', 'manage.py', 'tasks.py']

वेरिएंट 2.2 - लुकअप पुनरावर्ती

# lookup recursive
for dirpath, dirnames, filenames in os.walk(path):

    if not filenames:
        continue

    pythonic_files = fnmatch.filter(filenames, pattern)
    if pythonic_files:
        for file in pythonic_files:
            print('{}/{}'.format(dirpath, file))

परिणाम

./wsgi.py
./manage.py
./tasks.py
./temp/temp.py
./apps/diaries/urls.py
./apps/diaries/signals.py
./apps/diaries/actions.py
./apps/diaries/querysets.py
./apps/library/tests/test_forms.py
./apps/library/migrations/0001_initial.py
./apps/polls/views.py
./apps/polls/formsets.py
./apps/polls/reports.py
./apps/polls/admin.py

समाधान 3 - "पथलिब" का उपयोग करें

# lookup in current dir
path_ = pathlib.Path('.')
tuple(path_.glob(pattern))

# lookup recursive
tuple(path_.rglob(pattern))

टिप्पणियाँ:

  1. पायथन 3.4 पर परीक्षण किया गया
  2. मॉड्यूल "पैथलिब" केवल पायथन 3.4 में जोड़ा गया था
  3. Python 3.5 ने glob.glob https://docs.python.org/3.5/library/glob.html#glob.glob के साथ पुनरावर्ती देखने के लिए एक सुविधा जोड़ी । चूंकि मेरी मशीन पायथन 3.4 के साथ स्थापित है, मैंने इसका परीक्षण नहीं किया है।

9

अपनी फ़ाइलों को पुन: सूचीबद्ध करने के लिए os.walk का उपयोग करें

import os
root = "/home"
pattern = "145992"
alist_filter = ['jpg','bmp','png','gif'] 
path=os.path.join(root,"mydir_to_scan")
for r,d,f in os.walk(path):
    for file in f:
        if file[-3:] in alist_filter and pattern in file:
            print os.path.join(root,file)

टुकड़ा करने की आवश्यकता नहीं है; file.endswith(alist_filter)पर्याप्त है।
मार्टिन पीटर्स

5
import os

dir="/path/to/dir"
[x[0]+"/"+f for x in os.walk(dir) for f in x[2] if f.endswith(".jpg")]

यह आपको उनके पूर्ण पथ के साथ jpg फ़ाइलों की एक सूची देगा। आप सिर्फ फ़ाइल नाम के x[0]+"/"+fसाथ बदल सकते हैं f। आप f.endswith(".jpg")जो भी स्ट्रिंग स्थिति चाहें, उसके साथ भी बदल सकते हैं ।


3

आप भी एक और अधिक उच्च स्तरीय दृष्टिकोण की तरह (मैं लागू कर दिया है और के रूप में पैक कर सकते हैं findtools ):

from findtools.find_files import (find_files, Match)


# Recursively find all *.txt files in **/home/**
txt_files_pattern = Match(filetype='f', name='*.txt')
found_files = find_files(path='/home', match=txt_files_pattern)

for found_file in found_files:
    print found_file

के साथ स्थापित किया जा सकता है

pip install findtools

2

"Jpg" और "png" एक्सटेंशन के साथ "पथ / से / छवियों" में फ़ाइल नाम:

import os
accepted_extensions = ["jpg", "png"]
filenames = [fn for fn in os.listdir("path/to/images") if fn.split(".")[-1] in accepted_extensions]

यह
chb

1

आप पैथलिब का उपयोग कर सकते हैं जो पायथन मानक पुस्तकालय में 3.4 और इसके बाद के संस्करण में उपलब्ध है।

from pathlib import Path

files = [f for f in Path.cwd().iterdir() if f.match("145592*.jpg")]

1

आप पैटर्न को परिभाषित कर सकते हैं और इसके लिए जांच कर सकते हैं। यहाँ मैंने शुरू और अंत दोनों पैटर्न लिया है और फ़ाइलनाम में उनकी तलाश कर रहा हूं। FILES में एक डायरेक्टरी की सभी फाइलों की सूची है।

import os
PATTERN_START = "145592"
PATTERN_END = ".jpg"
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
for r,d,FILES in os.walk(CURRENT_DIR):
    for FILE in FILES:
        if PATTERN_START in FILE and PATTERN_END in FILE:
            print FILE

0

कैसे के बारे में str.split ()? आयात करने के लिए कुछ भी नहीं।

import os

image_names = [f for f in os.listdir(path) if len(f.split('.jpg')) == 2]


यह @ ramsey0 के उत्तर के समान प्रतीत होता है f.endswith('.jpg')(लेकिन यह भी चयन होगा filename.jpg.ext)
ajsimmo

-1

आप subprocess.check_ouput () के रूप में उपयोग कर सकते हैं

import subprocess

list_files = subprocess.check_output("ls 145992*.jpg", shell=True) 

बेशक, उद्धरण के बीच का तार कुछ भी हो सकता है जिसे आप शेल में निष्पादित करना चाहते हैं, और आउटपुट को स्टोर कर सकते हैं।


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