web-dev-qa-db-ja.com

ジェネレーターを使用してファイルシステムをトラバースするにはどうすればよいですか?

サブディレクトリおよびサブサブディレクトリ内のファイルを含む、ディレクトリ内のすべてのファイルをトラバースするためのユーティリティクラスを作成しようとしています。ジェネレーターはかっこいいので、ジェネレーターを使ってみました。しかし、私はひっかかった。


def grab_files(directory):
    for name in os.listdir(directory):
        full_path = os.path.join(directory, name)
        if os.path.isdir(full_path):
            yield grab_files(full_path)
        Elif os.path.isfile(full_path):
            yield full_path
        else:
            print('Unidentified name %s. It could be a symbolic link' % full_path)

ジェネレータがディレクトリに到達すると、新しいジェネレータのメモリ位置が生成されます。ディレクトリの内容はわかりません。

ジェネレーターに新しいジェネレーターの代わりにディレクトリの内容を生成させるにはどうすればよいですか?

ディレクトリ構造内のすべてのファイルを再帰的に一覧表示する単純なライブラリ関数がすでにある場合は、それについて教えてください。ライブラリ関数を複製するつもりはありません。

25
Evan Kroske

os.walk を使用できるのになぜ車輪を再発明するのか

import os
for root, dirs, files in os.walk(path):
    for name in files:
        print os.path.join(root, name)

os.walkは、ツリーをトップダウンまたはボトムアップでウォークすることにより、ディレクトリツリー内のファイル名を生成するジェネレータです。

58
Nadia Alramli

Os.walkソリューションに同意します

純粋な衒学的な目的のために、ジェネレータオブジェクトを直接返すのではなく、反復してみてください。


def grab_files(directory):
    for name in os.listdir(directory):
        full_path = os.path.join(directory, name)
        if os.path.isdir(full_path):
            for entry in grab_files(full_path):
                yield entry
        Elif os.path.isfile(full_path):
            yield full_path
        else:
            print('Unidentified name %s. It could be a symbolic link' % full_path)
12
thebat

Python 3.4以降、組み込みのpathlibモジュールからglob()メソッドを使用できます。

import pathlib
p = pathlib.Path('.')
list(p.glob('**/*'))    # lists all files recursively
10
EinfachToll

Python 3.4から、 Pathlib モジュールを使用できます。

In [48]: def alliter(p):
   ....:     yield p
   ....:     for sub in p.iterdir():
   ....:         if sub.is_dir():
   ....:             yield from alliter(sub)
   ....:         else:
   ....:             yield sub
   ....:             

In [49]: g = alliter(pathlib.Path("."))                                                                                                                                                              

In [50]: [next(g) for _ in range(10)]
Out[50]: 
[PosixPath('.'),
 PosixPath('.pypirc'),
 PosixPath('.python_history'),
 PosixPath('lshw'),
 PosixPath('.gstreamer-0.10'),
 PosixPath('.gstreamer-0.10/registry.x86_64.bin'),
 PosixPath('.gconf'),
 PosixPath('.gconf/apps'),
 PosixPath('.gconf/apps/gnome-terminal'),
 PosixPath('.gconf/apps/gnome-terminal/%gconf.xml')]

これは、オブジェクト指向バージョンの sjthebats answer に不可欠です。 Path.glob**パターンはディレクトリのみを返すことに注意してください!

8
gerrit

path.py を使用できます。残念ながら、作者のWebサイトはもう存在しませんが、PyPIからコードをダウンロードすることはできます。このライブラリは、osモジュールのパス関数のラッパーです。

_path.py_は、ディレクトリ内のすべてのファイルに対して再帰的に反復するジェネレータを返すwalkfiles()メソッドを提供します。

_>>> from path import path
>>> print path.walkfiles.__doc__
 D.walkfiles() -> iterator over files in D, recursively.

        The optional argument, pattern, limits the results to files
        with names that match the pattern.  For example,
        mydir.walkfiles('*.tmp') yields only files with the .tmp
        extension.

>>> p = path('/tmp')
>>> p.walkfiles()
<generator object walkfiles at 0x8ca75a4>
>>> 
_
0
Mike Mazur

gerritの答えへの補遺。もっと柔軟にしたかったのです。

特定のpthに一致するpattern内のすべてのファイルを一覧表示します。また、only_fileFalseです

from pathlib import Path

def walk(pth=Path('.'), pattern='*', only_file=True) :
    """ list all files in pth matching a given pattern, can also list dirs if only_file is False """
    if pth.match(pattern) and not (only_file and pth.is_dir()) :
        yield pth
    for sub in pth.iterdir():
        if sub.is_dir():
            yield from walk(sub, pattern, only_file)
        else:
            if sub.match(pattern) :
                yield sub
0
yota