以下のディレクトリを掘り下げることなくos.walk


102

指定os.walkしたディレクトリ内のファイルのみを返すように制限するにはどうすればよいですか?

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        for f in files:
            if os.path.splitext(f)[1] in whitelist:
                outputList.append(os.path.join(root, f))
            else:
                self._email_to_("ignore")
    return outputList

2
考えられる多数のアプローチとそれに伴うすべての警告のもう1つのケースは、この機能をPython標準ライブラリに追加する必要があることを示しています。
2016年

files_with_full_path = [f.path for f in os.scandir(dir) if f.is_file()]。のf.name代わりにファイル名のみを使用する必要がある場合f.path。これは、最速のソリューションであり、他のwalkor よりもはるかに高速です。stackoverflow.com/ a / 40347279/2441026をlistdir参照してください。
user136036

回答:


105

walklevel関数を使用します。

import os

def walklevel(some_dir, level=1):
    some_dir = some_dir.rstrip(os.path.sep)
    assert os.path.isdir(some_dir)
    num_sep = some_dir.count(os.path.sep)
    for root, dirs, files in os.walk(some_dir):
        yield root, dirs, files
        num_sep_this = root.count(os.path.sep)
        if num_sep + level <= num_sep_this:
            del dirs[:]

これはと同じように機能しos.walkますがlevel、再帰の深さを示すパラメーターを渡すことができます。


3
この関数は実際に構造全体を「ウォーク」し、特定のポイントの下のエントリを削除しますか?それとも、もっと賢いことが起こっていますか?これをコードで確認する方法すらわかりません。--python初心者
mathtick '19

1
@mathtick:目的のレベル以下のディレクトリが見つかると、そのサブディレクトリのすべてがサブディレクトリのリストから削除され、次に検索されます。したがって、それらは「ウォーク」されません。
nosklo 2010

2
dirsを「削除」する方法に苦労していたので、これを+1しました。私がしようとしたdirs = []dirs = Noneが、それらは動作しませんでした。 map(dirs.remove, dirs)機能しましたが、不要な「[なし]」メッセージが出力されました。それで、del dirs[:]具体的にはなぜですか?
ザックヤング

4
topdown=Falseos.walkで使用する場合、これは機能しないことに注意してください。第4回段落参照ドキュメントModifying dirnames when topdown is False has no effect on the behavior of the walk, because in bottom-up mode the directories in dirnames are generated before dirpath itself is generated.
dthor

3
@ZacharyYoungでdirs = []dirs = None関係のない新しいオブジェクトを作成してnameに割り当てるだけなので、機能しませんdirs。元のリストオブジェクトは、名前ではなくインプレースで変更する必要がありますdirs
nosklo 2018年

205

os.walkは使用しないでください。

例:

import os

root = "C:\\"
for item in os.listdir(root):
    if os.path.isfile(os.path.join(root, item)):
        print item

1
@ 576i:これはファイルとディレクトリを区別しません

4
@Alexandr os.path.isfileと区別os.path.isdirできます。以来、私は、それを得ることはありませんos.path.isfile'08ので、サンプルコードにあり、あなたのコメントは、'16からです。ディレクトリをウォークするつもりはないが、それをリストするつもりなので、これは明らかに良い答えです。
ダニエルF

@DanielF、ここで私が意味したことは、すべてのアイテムをループする必要があることですがwalk、dirsとfileの個別のリストがすぐに表示されます。

あ、そう。実際、アレックスの答えは(を使用して.next())より良くなるようで、あなたの考えにより近いものです。
ダニエルF

Python 3.5には、os.scandirより洗練されたファイルまたはディレクトリオブジェクトの相互作用を可能にする関数があります。以下の私の答えを参照しください
アクリプター

48

ソリューションは実際には非常に単純だと思います。

使用する

break

forループの最初の反復のみを実行するには、よりエレガントな方法が必要です。

for root, dirs, files in os.walk(dir_name):
    for f in files:
        ...
        ...
    break
...

初めてos.walkを呼び出すと、現在のディレクトリのチューリップが返され、次に次のループで次のディレクトリのコンテンツが返されます。

オリジナルのスクリプトを取り、改行を追加するだけです。

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        for f in files:
            if os.path.splitext(f)[1] in whitelist:
                outputList.append(os.path.join(root, f))
            else:
                self._email_to_("ignore")
        break
    return outputList

9
これは受け入れられるべき答えでした。「for f in files」ループの後に「break」を追加するだけで、再帰が停止します。また、topdown = Trueであることを確認することもできます。
Alecz 2016年

23

使用する提案listdirは良いものです。Python 2での質問に対する直接の答えはroot, dirs, files = os.walk(dir_name).next()です。

同等のPython 3構文は次のとおりです。 root, dirs, files = next(os.walk(dir_name))


1
ああ、私はそのエラーからあらゆる種類の面白いエラーを受け取っていました。ValueError:アンパックするには値が多すぎます
Setori 08年

1
いいね!しかし、ハックのように感じます。エンジンをオンにしたときのように、エンジンを1回転させてから、キーを引いてエンジンを停止させます。
ダニエルF

これを偶然見つけました。root, dirs, files = os.walk(dir_name).next()私に与えるAttributeError: 'generator' object has no attribute 'next'
エヴァン

3
@Evan、おそらくこれは2008年のものであり、Python 2構文を使用しているためです。Python 3ではroot, dirs, files = next(os.walk(dir_name))、次のように記述でき、変数root, dirs, filesdir_nameレベルのジェネレーターの変数にのみ対応します。
CervEd

13

os.listdir()whichを使用すると、特定のディレクトリ内の(ファイルとディレクトリの両方の)名前のリストを返します。ファイルとディレクトリを区別する必要がある場合はos.stat()、それぞれの名前を呼び出します。


9

トップディレクトリ以外の複雑な要件がある場合(たとえば、VCSディレクトリを無視するなど)、ディレクトリのリストを変更して、os.walkが再帰しないようにすることもできます。

つまり:

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        dirs[:] = [d for d in dirs if is_good(d)]
        for f in files:
            do_stuff()

注-単に再バインドするのではなく、リストを変更するように注意してください。明らかに、os.walkは外部の再バインドを認識していません。



4

と同じ考え方ですがlistdir、短くなっています。

[f for f in os.listdir(root_dir) if os.path.isfile(os.path.join(root_dir, f))]

3

私の2ペンスを投げ込むように感じました。

baselevel = len(rootdir.split("\\"))
for subdirs, dirs, files in os.walk(rootdir):
    curlevel = len(subdirs.split("\\"))
    if curlevel <= baselevel + 1:
        [do stuff]

2

Python 3では、これを行うことができました。

import os
dir = "/path/to/files/"

#List all files immediately under this folder:
print ( next( os.walk(dir) )[2] )

#List all folders immediately under this folder:
print ( next( os.walk(dir) )[1] )

これはPython 2でも機能します。第2レベルを取得する方法は?

2

Python 3.5以降では、のos.scandir代わりに使用できますos.listdir。文字列の代わりに、DirEntryオブジェクトのイテレータを返します。ドキュメントから:

scandir()代わりにを使用すると、listdir()ファイルタイプまたはファイル属性情報も必要とするコードのパフォーマンスが大幅に向上しますDirEntry。これは、ディレクトリのスキャン時にオペレーティングシステムが情報を提供すると、オブジェクトがこの情報を公開するためです。すべてのDirEntryメソッドがシステムコールを実行できますがis_dir()is_file()通常はシンボリックリンクのシステムコールのみが必要です。DirEntry.stat()Unixでは常にシステムコールが必要ですが、Windowsではシンボリックリンクに1つだけ必要です。

あなたは経由して、オブジェクトの名前にアクセスすることができDirEntry.name、その後の出力に相当しますos.listdir


1
だけでなく、あなたは、あなたが使う「できる」必要があります使用しscandir()、それはだとして、多くのよりも速くlistdir()。こちらのベンチマークをご覧ください:stackoverflow.com/a/40347279/2441026
user136036

1

次のこともできます。

for path, subdirs, files in os.walk(dir_name):
    for name in files:
        if path == ".": #this will filter the files in the current directory
             #code here

2
これはすべてのサブディレクトリとファイルを不必要にループしませんか?
Pieter

0

これは私がそれを解決した方法です

if recursive:
    items = os.walk(target_directory)
else:
    items = [next(os.walk(target_directory))]

...

0

listdirを使用すると問題が発生します。os.path.isdir(identifier)は絶対パスでなければなりません。あなたがするサブディレクトリを選ぶには:

for dirname in os.listdir(rootdir):
  if os.path.isdir(os.path.join(rootdir, dirname)):
     print("I got a subdirectory: %s" % dirname)

代替方法は、os.path.join()なしでテストを行うためにディレクトリに変更することです。



0

除外リストを作成し、fnmatchを使用してディレクトリ構造をスキップしてプロセスを実行します

excludes= ['a\*\b', 'c\d\e']
for root, directories, files in os.walk('Start_Folder'):
    if not any(fnmatch.fnmatch(nf_root, pattern) for pattern in excludes):
        for root, directories, files in os.walk(nf_root):
            ....
            do the process
            ....

'includes'と同じ:

if **any**(fnmatch.fnmatch(nf_root, pattern) for pattern in **includes**):

0

単純にa rangeを使用os.walkしてzip?と組み合わせないのはなぜですか?最善の解決策ではありませんが、うまくいくでしょう。

たとえば、次のようになります。

# your part before
for count, (root, dirs, files) in zip(range(0, 1), os.walk(dir_name)):
    # logic stuff
# your later part

Python 3で動作します。

また、A breakも単純です。(@Pieterからの回答を見てください)


0

アレックスの答えを少し変更しましたが、以下を使用してい__next__()ます:

print(next(os.walk('d:/'))[2]) または print(os.walk('d:/').__next__()[2])

[2]ことfileroot, dirs, file他の回答で述べました


0

os.walkが検出するすべてのディレクトリのルートフォルダが変更されます。root ==ディレクトリかどうかを確認することで解決します

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        if root == dir_name: #This only meet parent folder
            for f in files:
                if os.path.splitext(f)[1] in whitelist:
                    outputList.append(os.path.join(root, f))
                else:
                    self._email_to_("ignore")
    return outputList

0
import os

def listFiles(self, dir_name):
    names = []
    for root, directory, files in os.walk(dir_name):
        if root == dir_name:
            for name in files:
                names.append(name)
    return names

1
こんにちはリッチ、Stack Overflowへようこそ!このコードスニペットをありがとうございます。このコードスニペットは、限られた短期間のヘルプを提供する可能性があります。適切な説明は、なぜこれが問題の優れた解決策であるかを示すことにより、長期的な価値を大幅に改善し、他の同様の質問を持つ将来の読者にとってさらに役立つでしょう。回答を編集して、仮定を含め、説明を追加してください。
kenny_k
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.