পাইথন পুনরাবৃত্ত ফোল্ডার পড়া


224

আমার একটি সি ++ / ওবজে-সি ব্যাকগ্রাউন্ড রয়েছে এবং আমি কেবল পাইথন আবিষ্কার করছি (প্রায় এক ঘন্টা ধরে এটি লিখছি)। আমি একটি ফোল্ডার স্ট্রাকচারে টেক্সট ফাইলগুলির বিষয়গুলি পুনরাবৃত্তভাবে পড়তে একটি স্ক্রিপ্ট লিখছি।

আমার যে সমস্যাটি রয়েছে তা হ'ল আমি যে কোডটি লিখেছি তা কেবল একটি ফোল্ডারের গভীরে কাজ করবে। কোডটিতে (দেখতে #hardcoded path) কেন আমি দেখতে পাচ্ছি , পাইথনের সাথে আমি কীভাবে এগিয়ে যেতে পারি তা যেহেতু আমার অভিজ্ঞতাটি একেবারেই নতুন।

পাইথন কোড:

import os
import sys

rootdir = sys.argv[1]

for root, subFolders, files in os.walk(rootdir):

    for folder in subFolders:
        outfileName = rootdir + "/" + folder + "/py-outfile.txt" # hardcoded path
        folderOut = open( outfileName, 'w' )
        print "outfileName is " + outfileName

        for file in files:
            filePath = rootdir + '/' + file
            f = open( filePath, 'r' )
            toWrite = f.read()
            print "Writing '" + toWrite + "' to" + filePath
            folderOut.write( toWrite )
            f.close()

        folderOut.close()

উত্তর:


346

নিশ্চিত হয়ে নিন যে আপনি তিনটি ফেরতের মান বুঝতে পেরেছেন os.walk:

for root, subdirs, files in os.walk(rootdir):

নিম্নলিখিত অর্থ আছে:

  • root: বর্তমান পথ যা "দিয়ে গেছে"
  • subdirs: rootটাইপ ডিরেক্টরি ফাইল
  • files: ডিরেক্টরি ছাড়া অন্য ধরণের ফাইলগুলিতে root(অন্তর্ভুক্ত নয় subdirs)

এবং দয়া করে os.path.joinএকটি স্ল্যাশ সঙ্গে যুক্তি পরিবর্তে ব্যবহার করুন! আপনার সমস্যাটি হ'ল filePath = rootdir + '/' + file- আপনাকে অবশ্যই শীর্ষস্থানীয় ফোল্ডারের পরিবর্তে বর্তমানে "হাঁটা" ফোল্ডারটি একত্রিত করতে হবে। সুতরাং যে হতে হবে filePath = os.path.join(root, file)। বিটিডাব্লু "ফাইল" একটি অন্তর্নির্মিত, তাই আপনি সাধারণত এটিকে পরিবর্তনশীল নাম হিসাবে ব্যবহার করেন না।

আর একটি সমস্যা হ'ল আপনার লুপগুলি, যা এর মতো হওয়া উচিত, উদাহরণস্বরূপ:

import os
import sys

walk_dir = sys.argv[1]

print('walk_dir = ' + walk_dir)

# If your current working directory may change during script execution, it's recommended to
# immediately convert program arguments to an absolute path. Then the variable root below will
# be an absolute path as well. Example:
# walk_dir = os.path.abspath(walk_dir)
print('walk_dir (absolute) = ' + os.path.abspath(walk_dir))

for root, subdirs, files in os.walk(walk_dir):
    print('--\nroot = ' + root)
    list_file_path = os.path.join(root, 'my-directory-list.txt')
    print('list_file_path = ' + list_file_path)

    with open(list_file_path, 'wb') as list_file:
        for subdir in subdirs:
            print('\t- subdirectory ' + subdir)

        for filename in files:
            file_path = os.path.join(root, filename)

            print('\t- file %s (full path: %s)' % (filename, file_path))

            with open(file_path, 'rb') as f:
                f_content = f.read()
                list_file.write(('The file %s contains:\n' % filename).encode('utf-8'))
                list_file.write(f_content)
                list_file.write(b'\n')

যদি আপনি না জানতেন তবে withফাইলগুলির জন্য বিবৃতিটি একটি শর্টহ্যান্ড:

with open('filename', 'rb') as f:
    dosomething()

# is effectively the same as

f = open('filename', 'rb')
try:
    dosomething()
finally:
    f.close()

4
দুর্দান্ত, কী চলছে তা বোঝার জন্য প্রচুর প্রিন্ট এবং এটি পুরোপুরি কার্যকরভাবে কাজ করে। ধন্যবাদ! +1
ব্রুক উলফ

16
আমার মতো মূ /় / অসতর্ক যে কারও শিরোনাম ... এই কোড নমুনা প্রতিটি ডিরেক্টরিতে একটি txt ফাইল লিখে। আমি খুশি হয়েছি এটি একটি সংস্করণ নিয়ন্ত্রিত ফোল্ডারে পরীক্ষা করেছি, যদিও আমার একটি ক্লিনআপ স্ক্রিপ্ট লেখার জন্য প্রয়োজনীয় সবকিছু এখানেও রয়েছে :)
স্টিজি

এই দ্বিতীয় (দীর্ঘতম) কোড স্নিপেট খুব ভাল কাজ করেছে, আমাকে অনেক বিরক্তিকর কাজ বাঁচিয়েছে
উভচর

1
স্পীড যেহেতু স্পষ্টতই সর্বাধিক গুরুত্বপূর্ণ দিকটি os.walkখারাপ না, যদিও আমি আরও দ্রুততর পথে এগিয়ে এসেছি os.scandir। সমস্ত globসমাধান walk& এর চেয়ে অনেক ধীর scandir। আমার ফাংশন, সেইসাথে একটি সম্পূর্ণ গতি বিশ্লেষণ, এখানে পাওয়া যাবে: stackoverflow.com/a/59803793/2441026
user136036

112

আপনি যদি পাইথন 3.5 বা তার বেশি ব্যবহার করেন তবে আপনি এটি 1 লাইনে সম্পন্ন করতে পারেন।

import glob

for filename in glob.iglob(root_dir + '**/*.txt', recursive=True):
     print(filename)

ডকুমেন্টেশন হিসাবে উল্লিখিত

যদি পুনরাবৃত্তিযোগ্য সত্য হয়, '**' প্যাটার্নটি কোনও ফাইল এবং শূন্য বা আরও বেশি ডিরেক্টরি এবং সাব ডিরেক্টরিতে মিলবে।

আপনি যদি প্রতিটি ফাইল চান, আপনি ব্যবহার করতে পারেন

import glob

for filename in glob.iglob(root_dir + '**/*', recursive=True):
     print(filename)

প্রকারের ত্রুটি: iglob () একটি অপ্রত্যাশিত মূলশব্দ আর্গুমেন্ট 'পুনরাবৃত্ত'
পেয়েছে

1
শুরুতে উল্লিখিত হিসাবে, এটি কেবল পাইথন 3.5++
চিল্লারনান্দ

9
রুট_ডির অবশ্যই একটি পিছনে স্ল্যাশ থাকতে হবে (অন্যথায় আপনি প্রথম আর্গুমেন্ট হিসাবে 'ফোল্ডার / ** / *' এর পরিবর্তে 'ফোল্ডার ** / *' এর মতো কিছু পাবেন)। আপনি os.path.join (root_dir, ' * / ') ব্যবহার করতে পারেন তবে ওয়াইল্ডকার্ড পাথের সাথে os.path.join ব্যবহার করা গ্রহণযোগ্য কিনা তা আমি জানি না (যদিও এটি আমার অ্যাপ্লিকেশনের জন্য কার্যকর)।
drojf

@ চিল্লারানন্দ এবং আপনি কি দয়া করে এই উত্তরে কোডটিতে একটি মন্তব্য যুক্ত করতে পারেন যার root_dirজন্য একটি পিছনে স্ল্যাশ দরকার? এটি মানুষের সময় সাশ্রয় করবে (বা কমপক্ষে এটি আমার সময় সাশ্রয় করবে)। ধন্যবাদ।
ড্যান নিসেনবাউম

1
আমি যদি উত্তরের মতো এটি চালাতাম তবে এটি পুনরাবৃত্তি করে না। এই কাজ যাও recursively আমি সেটা বদলাতে হবে করুন: glob.iglob(root_dir + '**/**', recursive=True)। আমি পাইথন 3.8.2 মধ্যে কাজ করছি
মাইকি

38

ডেভ ওয়েবের সাথে সম্মত os.walkহন, গাছের প্রতিটি ডিরেক্টরিতে একটি আইটেম উত্পন্ন করবে। ঘটনাটি হ'ল, আপনাকে কেবল যত্ন করার দরকার নেই subFolders

এই জাতীয় কোড কাজ করা উচিত:

import os
import sys

rootdir = sys.argv[1]

for folder, subs, files in os.walk(rootdir):
    with open(os.path.join(folder, 'python-outfile.txt'), 'w') as dest:
        for filename in files:
            with open(os.path.join(folder, filename), 'r') as src:
                dest.write(src.read())

3
সুন্দর. এটি পাশাপাশি কাজ করে। তবে আমি অ্যান্ডিডগের সংস্করণটিকে বেশি পছন্দ করি যদিও এটি দীর্ঘতর কারণ এটি পাইথনের একজন শিক্ষানবিস হিসাবে আরও স্পষ্ট। +1
ব্রুক উলফ

20

টিএল; ডিআর: এটি find -type fনীচের সমস্ত ফোল্ডারে সমস্ত ফাইল ও বর্তমান ফাইল সহ সমেত সমতুল্য :

for currentpath, folders, files in os.walk('.'):
    for file in files:
        print(os.path.join(currentpath, file))

যেমন ইতিমধ্যে অন্যান্য os.walk()উত্তরে উল্লিখিত হয়েছে, উত্তরটি তবে এটি আরও ভালভাবে ব্যাখ্যা করা যেতে পারে। এটা বেশ সহজ! আসুন এই গাছ দিয়ে চলুন:

docs/
└── doc1.odt
pics/
todo.txt

এই কোড সহ:

for currentpath, folders, files in os.walk('.'):
    print(currentpath)

currentpathবর্তমান ফোল্ডার দিকে তাকিয়ে নেই। এটি আউটপুট দেবে:

.
./docs
./pics

সুতরাং এটি তিনবার লুপ করে, কারণ এখানে তিনটি ফোল্ডার রয়েছে: বর্তমান একটি docsএবং pics। প্রতিটি লুপে, এটি ভেরিয়েবলগুলি foldersএবং filesসমস্ত ফোল্ডার এবং ফাইলগুলি পূরণ করে। আসুন তাদের দেখান:

for currentpath, folders, files in os.walk('.'):
    print(currentpath, folders, files)

এটি আমাদের দেখায়:

# currentpath  folders           files
.              ['pics', 'docs']  ['todo.txt']
./pics         []                []
./docs         []                ['doc1.odt']

সুতরাং প্রথম লাইনে আমরা দেখতে পাচ্ছি যে আমরা ফোল্ডারে রয়েছি ., এতে দুটি ফোল্ডার রয়েছে picsএবং docsএটি একটি ফাইল রয়েছে todo.txt। আপনাকে সেই ফোল্ডারগুলিতে পুনরাবৃত্তি করতে কিছু করতে হবে না, কারণ আপনি দেখতে পাচ্ছেন, এটি স্বয়ংক্রিয়ভাবে পুনরাবৃত্তি হয় এবং কেবল কোনও সাবফোল্ডারগুলিতে ফাইল দেয়। এবং এর যে কোনও সাবফোল্ডার (যদিও আমাদের কাছে এটি উদাহরণ নেই)।

যদি আপনি কেবল সমস্ত ফাইলের মধ্যে লুপ করতে চান তবে এর সমতুল্য find -type fআপনি এটি করতে পারেন:

for currentpath, folders, files in os.walk('.'):
    for file in files:
        print(os.path.join(currentpath, file))

এই ফলাফলগুলি:

./todo.txt
./docs/doc1.odt

9

pathlibগ্রন্থাগার ফাইলগুলির সাথে কাজ জন্য সত্যিই মহান। আপনি Pathযেমন একটি বস্তুর উপর পুনরাবৃত্ত গ্লোব করতে পারেন।

from pathlib import Path

for elem in Path('/path/to/my/files').rglob('*.*'):
    print(elem)

6

যদি আপনি প্রদত্ত দিরের অধীনে সমস্ত পথের সমতল তালিকা চান ( find .শেলের মতো):

   files = [ 
       os.path.join(parent, name)
       for (parent, subdirs, files) in os.walk(YOUR_DIRECTORY)
       for name in files + subdirs
   ]

বেস ডিয়ারের নীচে কেবলমাত্র ফাইলের পুরো পথ অন্তর্ভুক্ত করতে, ছেড়ে যান + subdirs


6
import glob
import os

root_dir = <root_dir_here>

for filename in glob.iglob(root_dir + '**/**', recursive=True):
    if os.path.isfile(filename):
        with open(filename,'r') as file:
            print(file.read())

**/**সমস্ত ফাইল পুনরাবৃত্তভাবে অন্তর্ভুক্ত পেতে ব্যবহৃত হয় directory

if os.path.isfile(filename)filenameভেরিয়েবল কিনা তা পরীক্ষা করতে ব্যবহৃত হয়file বা directory, যদি ফাইল তারপর আমরা যে ফাইল পড়তে পারেন। এখানে আমি ফাইল মুদ্রণ করছি।


6

আমি নিম্নলিখিতটি সবচেয়ে সহজ বলে খুঁজে পেয়েছি

from glob import glob
import os

files = [f for f in glob('rootdir/**', recursive=True) if os.path.isfile(f)]

ব্যবহারে glob('some/path/**', recursive=True)সমস্ত ফাইল পাওয়া যায় তবে এতে ডিরেক্টরিটির নামও অন্তর্ভুক্ত থাকে। if os.path.isfile(f)শর্ত যুক্ত করে কেবল বিদ্যমান ফাইলগুলিতে এই তালিকাটি ফিল্টার করে


3

os.path.join()আপনার পাথ নির্মাণ করতে ব্যবহার করুন - এটি আরও কম:

import os
import sys
rootdir = sys.argv[1]
for root, subFolders, files in os.walk(rootdir):
    for folder in subFolders:
        outfileName = os.path.join(root,folder,"py-outfile.txt")
        folderOut = open( outfileName, 'w' )
        print "outfileName is " + outfileName
        for file in files:
            filePath = os.path.join(root,file)
            toWrite = open( filePath).read()
            print "Writing '" + toWrite + "' to" + filePath
            folderOut.write( toWrite )
        folderOut.close()

দেখে মনে হচ্ছে এই কোডটি কেবল 2 স্তরের (বা আরও গভীর) ফোল্ডারগুলির জন্য কাজ করে। তবুও এটি আমার কাছাকাছি আসে
ব্রুক উলফ

1

os.walkডিফল্ট অনুসারে পুনরাবৃত্তির পদচারণা করে। প্রতিটি দিরের জন্য, মূল থেকে শুরু করে এটি 3-টিপল দেয় (দিরপাথ, ডাইরনাম, ফাইলের নাম)

from os import walk
from os.path import splitext, join

def select_files(root, files):
    """
    simple logic here to filter out interesting files
    .py files in this example
    """

    selected_files = []

    for file in files:
        #do concatenation here to get full path 
        full_path = join(root, file)
        ext = splitext(file)[1]

        if ext == ".py":
            selected_files.append(full_path)

    return selected_files

def build_recursive_dir_tree(path):
    """
    path    -    where to begin folder scan
    """
    selected_files = []

    for root, dirs, files in walk(path):
        selected_files += select_files(root, files)

    return selected_files

1
পাইথন 2.6 ইন walk() Do রিকার্সিভ তালিকা ফিরে যান। আমি আপনার কোডটি চেষ্টা করেছি এবং অনেক পুনরাবৃত্তি সহ একটি তালিকা পেয়েছি ... আপনি যদি "সাবফোল্ডারগুলিতে # পুনরাবৃত্ত কল" - মন্তব্যে কেবল লাইনগুলি সরিয়ে থাকেন - এটি ঠিক কাজ করে
২২

1

এটা চেষ্টা কর:

import os
import sys

for root, subdirs, files in os.walk(path):

    for file in os.listdir(root):

        filePath = os.path.join(root, file)

        if os.path.isdir(filePath):
            pass

        else:
            f = open (filePath, 'r')
            # Do Stuff

আপনার যদি ইতিমধ্যে ডিরেক্টরি তালিকাটি ফাইল এবং ডিরেক্টরিতে ওয়াক () থেকে বিভক্ত হয়ে থাকে তখন আপনি কেন অন্য তালিকাডির () এবং তারপরে ইসডির () করবেন? দেখে মনে হচ্ছে এটি বড় গাছগুলিতে ধীরে ধীরে ধীরে ধীরে হবে (একের পরিবর্তে তিনটি সাইস্কেল করুন: 1 = হাঁটা, 2 = তালিকাডির, 3 = ইসডির, কেবল 'সাবডিয়ার' এবং 'ফাইলগুলি' দিয়ে হাঁটুন এবং লুপ করুন)।
লুক

0

আমি মনে করি সমস্যাটি হ'ল আপনি আউটপুট প্রক্রিয়াজাত করছেন না os.walk সঠিকভাবে ।

প্রথমত, পরিবর্তন করুন:

filePath = rootdir + '/' + file

প্রতি:

filePath = root + '/' + file

rootdirআপনার স্থির সূচনা ডিরেক্টরি; rootএকটি ডিরেক্টরি দ্বারা ফিরে os.walk

দ্বিতীয়ত, আপনার ফাইল প্রসেসিং লুপটি ইনডেন্ট করার দরকার নেই, কারণ এটি প্রতিটি উপ-ডিরেক্টরিতে এটি চালানোর কোনও মানে হয় না। আপনি rootপ্রতিটি উপ-ডিরেক্টরিতে সেট হয়ে যাবেন । ডিরেক্টরিগুলি নিজেই কিছু করতে না চাইলে আপনাকে নিজের হাতে উপ-ডিরেক্টরিগুলি প্রক্রিয়া করার প্রয়োজন হবে না।


প্রতিটি উপ ডিরেক্টরিতে আমার ডেটা রয়েছে তাই প্রতিটি ডিরেক্টরিের সামগ্রীর জন্য আমার আলাদা পাঠ্য ফাইল থাকা দরকার।
ব্রুক উলফ

@ ব্রোক: ফাইলগুলি হ'ল বর্তমান ডিরেক্টরিতে থাকা ফাইলগুলির তালিকা। সুতরাং ইন্ডেন্টেশন আসলেই ভুল। আপনি এতে লিখছেন filePath = rootdir + '/' + file, এটি ঠিক শোনাচ্ছে না: ফাইলটি বর্তমান ফাইলগুলির তালিকা থেকে, সুতরাং আপনি প্রচুর বিদ্যমান ফাইলগুলিতে লিখছেন?
অলোক সিংহল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.