পাইথনে তাত্ক্ষণিক সমস্ত উপ-ডিরেক্টরি কীভাবে পাবেন


150

আমি একটি সাধারণ পাইথন স্ক্রিপ্ট লেখার চেষ্টা করছি যা সমস্ত উপ-ডিরেক্টরিতে (কয়েকটি ব্যতিক্রম বাদে) একটি সূচি.টি.পি.এল.কে সূচক। Html অনুলিপি করবে।

আমি উপ-ডিরেক্টরিগুলির তালিকা পাওয়ার চেষ্টা করে জড়িয়ে যাচ্ছি।


11
আপনি দেখতে পাবেন যে এই পূর্ববর্তী এসও প্রশ্নের গৃহীত উত্তরটি সমস্যার সমাধান করে: stackoverflow.com/questions/120656/directory-listing-in-python
জারেট হার্ডি

উত্তর:


31

সমস্ত বর্তমান উপ-ডিরেক্টরিতে পুরো পথটি ফিরিয়ে আনতে আমি বিভিন্ন ক্রিয়ায় কিছু গতি পরীক্ষা করেছি

tl; dr: সর্বদা ব্যবহার করুন scandir:

list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]

বোনাস: scandirআপনি কেবল কেবল f.nameপরিবর্তে ব্যবহার করে ফোল্ডারের নামগুলি পেতে পারেন f.path

এটি (পাশাপাশি নীচে অন্যান্য সমস্ত ফাংশন) প্রাকৃতিক বাছাই ব্যবহার করবে না । এর অর্থ ফলাফলগুলি এইভাবে সাজানো হবে: 1, 10, 2। প্রাকৃতিক বাছাই পেতে (1, 2, 10), দয়া করে একবার দেখুন https://stackoverflow.com/a/48030307/2441026




ফলাফল : এর scandirচেয়ে 3x দ্রুত walk, listdir(ফিল্টার সহ) 32x দ্রুত , 35x এর চেয়ে দ্রুত Pathlibএবং 36x এর চেয়ে দ্রুত listdirএবং 37x (!) এর চেয়ে দ্রুত glob

Scandir:           0.977
Walk:              3.011
Listdir (filter): 31.288
Pathlib:          34.075
Listdir:          35.501
Glob:             36.277

ডাব্লু 7x64, পাইথন 3.8.1 এর সাথে পরীক্ষিত। 440 সাবফোল্ডার সহ ফোল্ডার।
আপনি যদি ভাবছেন যে listdiros.path.join () দু'বার না করে গতি বাড়ানো যায় তবে হ্যাঁ, তবে পার্থক্যটি মূলত অস্তিত্বহীন।

কোড:

import os
import pathlib
import timeit
import glob

path = r"<example_path>"



def a():
    list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]
    # print(len(list_subfolders_with_paths))


def b():
    list_subfolders_with_paths = [os.path.join(path, f) for f in os.listdir(path) if os.path.isdir(os.path.join(path, f))]
    # print(len(list_subfolders_with_paths))


def c():
    list_subfolders_with_paths = []
    for root, dirs, files in os.walk(path):
        for dir in dirs:
            list_subfolders_with_paths.append( os.path.join(root, dir) )
        break
    # print(len(list_subfolders_with_paths))


def d():
    list_subfolders_with_paths = glob.glob(path + '/*/')
    # print(len(list_subfolders_with_paths))


def e():
    list_subfolders_with_paths = list(filter(os.path.isdir, [os.path.join(path, f) for f in os.listdir(path)]))
    # print(len(list(list_subfolders_with_paths)))


def f():
    p = pathlib.Path(path)
    list_subfolders_with_paths = [x for x in p.iterdir() if x.is_dir()]
    # print(len(list_subfolders_with_paths))



print(f"Scandir:          {timeit.timeit(a, number=1000):.3f}")
print(f"Listdir:          {timeit.timeit(b, number=1000):.3f}")
print(f"Walk:             {timeit.timeit(c, number=1000):.3f}")
print(f"Glob:             {timeit.timeit(d, number=1000):.3f}")
print(f"Listdir (filter): {timeit.timeit(e, number=1000):.3f}")
print(f"Pathlib:          {timeit.timeit(f, number=1000):.3f}")

1
আপনাকে ধন্যবাদ জানাতে চাই, সত্যিই এটি খুঁজছিল। দুর্দান্ত বিশ্লেষণ।
সিঙ

225
import os
def get_immediate_subdirectories(a_dir):
    return [name for name in os.listdir(a_dir)
            if os.path.isdir(os.path.join(a_dir, name))]

76

কেন কেউ উল্লেখ করেনি glob? globআপনাকে ইউনিক্স-স্টাইলের পথের নামটি ব্যবহার করতে দেয় এবং একাধিক পাথের নামের সন্ধানের প্রায় প্রতিটি ক্ষেত্রেই আমি কাজ করতে চলেছি। এটি এটিকে খুব সহজ করে তোলে:

from glob import glob
paths = glob('*/')

নোট করুন যে globচূড়ান্ত স্ল্যাশ (ইউনিক্স হিসাবে) সহ ডিরেক্টরিটি ফিরিয়ে দেবে যখন বেশিরভাগ pathভিত্তিক সমাধান চূড়ান্ত স্ল্যাশ বাদ দেবে।


3
ভাল সমাধান, সহজ এবং কাজ। যারা চূড়ান্ত স্ল্যাশ চান না তাদের জন্য, তিনি এটি ব্যবহার করতে পারেন paths = [ p.replace('/', '') for p in glob('*/') ]
ইভান হু

5
এটি দিয়ে শেষ অক্ষরটি কেবল কাটা নিরাপদ হতে পারে [p[:-1] for p in paths], কারণ এই প্রতিস্থাপন পদ্ধতিটি ফাইলের নামের কোনও পালানো ফরোয়ার্ড স্ল্যাশগুলি প্রতিস্থাপন করবে (এটি সাধারণ নয়) common
এরি

3
এমনকি নিরাপদ, পিছনের স্ল্যাশগুলি সরাতে স্ট্রিপ ('/') ব্যবহার করুন। এইভাবে গ্যারান্টি দেয় যে আপনি এমন কোনও অক্ষর কেটে ফেলবেন না যা ফরোয়ার্ড স্ল্যাশ হয় না
এলিজার মিরন

8
নির্মাণের মাধ্যমে আপনার পিছনে স্ল্যাশ হওয়ার নিশ্চয়তা রয়েছে (সুতরাং এটি নিরাপদ নয়) তবে আমি মনে করি এটি আরও পঠনযোগ্য। আপনি অবশ্যই এর rstripপরিবর্তে অবশ্যই ব্যবহার করতে চান strip, যেহেতু পরেরগুলি কোনও সম্পূর্ণ যোগ্য পাথকে আপেক্ষিক পথে পরিণত করবে।
এরি

7
আমি যেমন পাইথন নবজাতকদের জন্য @ari মন্তব্যের পরিপূরক: strip('/')'/' শুরু করা এবং অনুসরণ করা উভয়ই সরিয়ে ফেলব , rstrip('/')কেবল অনুসরণকারীটিকে সরিয়ে ফেলবে
তিতো

35

" বর্তমান ডিরেক্টরিতে সমস্ত উপ-ডিরেক্টরিগুলির একটি তালিকা পাওয়া " পরীক্ষা করুন।

এখানে পাইথন 3 সংস্করণ রয়েছে:

import os

dir_list = next(os.walk('.'))[1]

print(dir_list)

2
অত্যন্ত চতুর। দক্ষতা কোনও বিষয় নয় (যদিও এটি সম্পূর্ণরূপে ঘটে ) তবে আমি বা কৌতূহল ভিত্তিক জেনারেটর এক্সপ্রেশনটি (s.rstrip("/") for s in glob(parent_dir+"*/"))আরও সময় দক্ষ কিনা তা সম্পর্কে আমি আগ্রহী । আমার স্বজ্ঞাত সন্দেহ করে একটি হল stat()ভিত্তিক os.walk()সমাধান করা উচিত গভীর দ্রুত শেল-শৈলী globbing চেয়ে। দুঃখের বিষয়, আমার ইচ্ছাশক্তি নেই timeitএবং প্রকৃতপক্ষে এটি সন্ধান করতে পারি।
সিসিল কারি

3
নোট করুন যে এটি পূর্বনির্ধারিত প্যারেন্ট ডিরেক্টরি নাম ব্যতীত উপ-ডিরেক্টরি নামগুলি প্রদান করে।
পল চেরনোচ

19
import os, os.path

কোনও ডিরেক্টরিতে তাত্ক্ষণিক সাব-ডিরেক্টরিগুলি পেতে (পুরো-পথ) পেতে:

def SubDirPath (d):
    return filter(os.path.isdir, [os.path.join(d,f) for f in os.listdir(d)])

সর্বশেষ (নতুন) উপ-ডিরেক্টরি পেতে:

def LatestDirectory (d):
    return max(SubDirPath(d), key=os.path.getmtime)

একটি তালিকা পেতে , কেবল যুক্ত করুন list( filter(...) )
ব্যবহারকারীর 136036

12

os.walk এই পরিস্থিতিতে আপনার বন্ধু।

ডকুমেন্টেশন থেকে সরাসরি:

ওয়াক () ডিরেক্টরিটিকে নীচে বা নীচে উপরের দিকে হাঁটার মাধ্যমে ডিরেক্টরি ট্রিতে ফাইলের নাম উত্পন্ন করে। ডিরেক্টরি শীর্ষে গাছের প্রতিটি ডিরেক্টরিতে (শীর্ষে নিজেও এটি অন্তর্ভুক্ত), এটি একটি 3-টিপল (dirpath, dirnames, ফাইলের নাম) দেয়।


1
কেবল সচেতন হন যে আপনি যদি কেবলমাত্র প্রথম-স্তরের সাব-ডিরেক্টরিগুলি চান তবে রিটার্ন মানগুলির প্রথম সেটের পরে wal.ওয়াকের পুনরাবৃত্তিটি ভেঙে ফেলুন।
yoyo

11

এই পদ্ধতিটি দুর্দান্তভাবে একসাথে করে।

from glob import glob
subd = [s.rstrip("/") for s in glob(parent_dir+"*/")]

7

টুইস্টেড ফাইলপথ মডিউল ব্যবহার:

from twisted.python.filepath import FilePath

def subdirs(pathObj):
    for subpath in pathObj.walk():
        if subpath.isdir():
            yield subpath

if __name__ == '__main__':
    for subdir in subdirs(FilePath(".")):
        print "Subdirectory:", subdir

যেহেতু কিছু মন্তব্যকারীরা এটির জন্য টুইস্টেড লাইব্রেরিগুলি ব্যবহার করার সুবিধা কী তা জিজ্ঞাসা করেছেন, তাই আমি এখানে মূল প্রশ্নের বাইরে কিছুটা এগিয়ে যাব।


আছে কিছু উন্নত ডকুমেন্টেশন একটি শাখা যে FilePath সুবিধার ব্যাখ্যা হয়; আপনি এটি পড়তে চাইতে পারেন।

আরও নির্দিষ্টভাবে এই উদাহরণে: স্ট্যান্ডার্ড লাইব্রেরি সংস্করণ থেকে ভিন্ন, এই ফাংশনটি কোনও আমদানি ছাড়াই প্রয়োগ করা যেতে পারে । "সাবডিয়ার্স" ফাংশনটি সম্পূর্ণ জেনারিক, এতে এটি যুক্তি ব্যতীত অন্য কিছুতে কাজ করে না। স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করে ফাইলগুলি অনুলিপি করতে এবং সরানোর জন্য আপনাকে open"বিল্টিন," listdir", সম্ভবত" isdir"বা" os.walk"বা" shutil.copy"এর উপর নির্ভর করতে হবে । সম্ভবত " os.path.join"। সত্যিকারের ফাইলটি সনাক্ত করার জন্য আপনার একটি স্ট্রিং প্রয়োজন যুক্তি দিয়েছিল তা উল্লেখ করার প্রয়োজন নেই। আসুন পুরো বাস্তবায়নটি একবার দেখে নিই যা প্রতিটি ডিরেক্টরিটির "index.tpl" কে "index.html" এ অনুলিপি করবে:

def copyTemplates(topdir):
    for subdir in subdirs(topdir):
        tpl = subdir.child("index.tpl")
        if tpl.exists():
            tpl.copyTo(subdir.child("index.html"))

উপরের "সাবডিয়ার্স" ফাংশনটি যে কোনও-পছন্দসই FilePathঅবজেক্টে কাজ করতে পারে । যার অর্থ, অন্যান্য জিনিসগুলির মধ্যেও ZipPathobjects দুর্ভাগ্যবশত ZipPathএখনই কেবল পঠনযোগ্য, তবে এটি লেখার পক্ষে সমর্থন বাড়ানো যেতে পারে।

পরীক্ষার উদ্দেশ্যে আপনি নিজের জিনিসগুলিও পাস করতে পারেন। এখানে প্রস্তাবিত ওস.পাথ-ব্যবহার করে এপিআই পরীক্ষা করার জন্য, আপনাকে আমদানি করা নাম এবং অন্তর্নিহিত নির্ভরতা সহ বাঁদর করতে হবে এবং আপনার পরীক্ষাগুলি কাজে লাগানোর জন্য সাধারণত কালো যাদু করতে হয়। ফাইলপথ দিয়ে আপনি এমন কিছু করুন:

class MyFakePath:
    def child(self, name):
        "Return an appropriate child object"

    def walk(self):
        "Return an iterable of MyFakePath objects"

    def exists(self):
        "Return true or false, as appropriate to the test"

    def isdir(self):
        "Return true or false, as appropriate to the test"
...
subdirs(MyFakePath(...))

যেহেতু আমার কাছে টুইস্টের সামান্য এক্সপোজার রয়েছে তাই আমি সবসময় অতিরিক্ত তথ্য এবং উদাহরণগুলিকে স্বাগত জানাই; এই উত্তরটির জন্য এটি দেখতে সুন্দর is এই কথাটি বলার পরে, যেহেতু এই পদ্ধতির অন্তর্নির্মিত পাইথন মডিউলগুলি এবং একটি বাঁকানো ইনস্টল ব্যবহার করার চেয়ে যথেষ্ট কাজ প্রয়োজন বলে মনে হচ্ছে, আপনি এটির উত্তর যুক্ত করতে পারার কোনও সুবিধা আছে কি?
জারেট হার্ডি

1
গ্লিফের উত্তর সম্ভবত এই বিষয়টি দ্বারা অনুপ্রাণিত হয়েছিল যে টুইস্টলোর .tpl ফাইলগুলিও ব্যবহার করে।
কনস্টান্টিন

ভাল, স্পষ্টভাবে আমি স্প্যানিশ অনুসন্ধানের প্রত্যাশা করি না :-) আমি ধরে নিয়েছিলাম "* .tpl" কিছু বিমূর্ত এক্সটেনশনের অর্থ "টেমপ্লেট", এবং কোনও নির্দিষ্ট বাঁকানো টেম্পলেট নয় (আমি অনেকগুলি ব্যবহার করে .tpl দেখেছি) সব পরে ভাষা)। জানা ভাল.
জারেট হার্ডি

+1 সুতরাং সম্ভাব্য মোচড়ের কোণে প্যাঁচানোর জন্য, যদিও আমি এখনও বুঝতে চাইছি টুইস্টড 'ফাইলপথ' অবজেক্ট এবং 'ওয়াক ()' ফাংশনটি স্ট্যান্ডার্ড এপিআইতে কী যুক্ত করে।
জারেট হার্ডি

ব্যক্তিগতভাবে আমি পাই "ফাইলপথ.ওয়াক () পাথ অবজেক্টস দেয়" "স্মরণ করা অনেক সহজ" "ওএসওয়াক 3-টুপল দির, ডায়ার, ফাইল দেয়" than তবে অন্যান্য সুবিধাও রয়েছে। ফাইলপথ পলিমারফিজমের অনুমতি দেয়, যার অর্থ আপনি ফাইল সিস্টেম ছাড়া অন্য জিনিসগুলিও ট্র্যাভার করতে পারেন। উদাহরণস্বরূপ, আপনি আমার 'সাবডিয়ার্স' ফাংশনে একটি মোচড়.পিথন.জিপথ.জিপআর্কাইভ পাস করতে পারেন এবং ফাইলপথগুলির পরিবর্তে জিপপথগুলির একটি জেনারেটর বের করতে পারেন; আপনার যুক্তি পরিবর্তন হয় না, তবে আপনার অ্যাপ্লিকেশনটি এখন যাদুকরীভাবে জিপ ফাইলগুলি পরিচালনা করে। আপনি যদি এটি পরীক্ষা করতে চান তবে আপনাকে কেবল একটি জিনিস সরবরাহ করতে হবে, আপনাকে আসল ফাইলগুলি লিখতে হবে না।
গ্লাইফ

4

আমি সবেমাত্র ভিএমওয়্যার ভার্চুয়াল মেশিনগুলিকে সরানোর জন্য কিছু কোড লিখেছি os.pathএবং shutilসাব-ডিরেক্টরিগুলির মধ্যে ফাইল অনুলিপিটি ব্যবহার করে শেষ করেছি ।

def copy_client_files (file_src, file_dst):
    for file in os.listdir(file_src):
            print "Copying file: %s" % file
            shutil.copy(os.path.join(file_src, file), os.path.join(file_dst, file))

এটি ভয়ানক মার্জিত নয়, তবে এটি কার্যকর হয়।


1

এখানে একটি উপায়:

import os
import shutil

def copy_over(path, from_name, to_name):
  for path, dirname, fnames in os.walk(path):
    for fname in fnames:
      if fname == from_name:
        shutil.copy(os.path.join(path, from_name), os.path.join(path, to_name))


copy_over('.', 'index.tpl', 'index.html')

-1: কাজ করবে না, যেহেতু shutil.copy বর্তমান dir এ অনুলিপি করবে, সুতরাং আপনি প্রতিটি 'index.tpl' এর জন্য সাবডিরেক্টরি ট্রিতে সন্ধানের জন্য একবার বর্তমান ডায়ারে 'index.html' ওভাররাইটিং শেষ করবেন।
নসক্লো

1

আমাকে পথ.পি লাইব্রেরির উল্লেখ করতে হবে , যা আমি প্রায়শই ব্যবহার করি।

তাত্ক্ষণিক সাব-ডাইরেক্টরিগুলি আনার মতো সাধারণ হয়ে উঠুন:

my_dir.dirs()

পুরো কাজের উদাহরণটি হ'ল:

from path import Path

my_directory = Path("path/to/my/directory")

subdirs = my_directory.dirs()

এনবি: আমার_ডাইরেক্টরিটি এখনও স্ট্রিং হিসাবে ম্যানিপুলেট করা যায়, যেহেতু পাথ স্ট্রিংয়ের একটি সাবক্লাস, তবে পথগুলি পরিচালনা করার জন্য দরকারী পদ্ধতিগুলির একটি গুচ্ছ সরবরাহ করে


1
def get_folders_in_directories_recursively(directory, index=0):
    folder_list = list()
    parent_directory = directory

    for path, subdirs, _ in os.walk(directory):
        if not index:
            for sdirs in subdirs:
                folder_path = "{}/{}".format(path, sdirs)
                folder_list.append(folder_path)
        elif path[len(parent_directory):].count('/') + 1 == index:
            for sdirs in subdirs:
                folder_path = "{}/{}".format(path, sdirs)
                folder_list.append(folder_path)

    return folder_list

নিম্নলিখিত ফাংশন হিসাবে বলা যেতে পারে:

get_folders_in_directories_recursively (ডিরেক্টরি, সূচক = 1) -> প্রথম স্তরের ফোল্ডারগুলির তালিকা দেয়

get_folders_in_directories_recursively (ডিরেক্টরি) -> সমস্ত উপ ফোল্ডার দেয়



1
একটি শ্রেণীর ভিতরে ব্যবহার করছিল, আপডেট করেছে
কনিষ ম্যাথিউ

0
import glob
import os

def child_dirs(path):
     cd = os.getcwd()        # save the current working directory
     os.chdir(path)          # change directory 
     dirs = glob.glob("*/")  # get all the subdirectories
     os.chdir(cd)            # change directory to the script original location
     return dirs

child_dirsফাংশন একটি পাথ একটি ডিরেক্টরি নেয় এবং একটি তালিকা ফেরৎ অবিলম্বে সাবডিরেক্টরি এতে।

dir
 |
  -- dir_1
  -- dir_2

child_dirs('dir') -> ['dir_1', 'dir_2']

0
import pathlib


def list_dir(dir):
    path = pathlib.Path(dir)
    dir = []
    try:
        for item in path.iterdir():
            if item.is_dir():
                dir.append(item)
        return dir
    except FileNotFoundError:
        print('Invalid directory')

0

পাথলিব ব্যবহার করে একটি লাইনার:

list_subfolders_with_paths = [p for p in pathlib.Path(path).iterdir() if p.is_dir()]
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.