2016-11-02 23 views
3

でディレクトリをターゲットに、私のスクリプトが検索され、あまりにも多くのディレクトリ:により大規模かつ複雑なディレクトリ構造にos.walk

root-- 
    | 
    --Project A-- 
        | 
        -- Irrelevant 
        -- Irrelevant 
        -- TARGET 
    | 
    --Project B-- 
        | 
        -- Irrelevant 
        -- TARGET 
        -- Irrelevant 
    | 
    -- Irrelevant -- 
         | 
         --- Irrelevant 

ターゲットディレクトリは、私が横断する必要がある唯一のものであり、それは一貫しています各プロジェクトの名前(ここではTargetと呼ぶ)。

私はこの質問を見て:

Excluding directories in os.walk

代わりのを除く、私は「ターゲット」「ルート」レベルではないディレクトリが、1レベル下を含める必要があります。私はのように何かをしようとした

def walker(path): 
    for dirpath, dirnames, filenames in os.walk(path): 
     dirnames[:] = set(['TARGET']) 

しかし、この1つのエフェクトのルートディレクトリ(それによって、トラバースする必要があるすべてのディレクトリを無視して、プロジェクトA、プロジェクトB ...)

+3

'' TARGET 'がdirnamesの場合:dirnames [:] = [' TARGET '] '... – Bakuriu

+0

' glob.glob'を使ってまず 'target'サブディレクトリのリストを取得してから' os .listdir'または 'os.walk'を実行しますか? –

+0

@CABつまり、 'walk'はルートディレクトリを通過しません。 –

答えて

3

あなたのコードの問題は、あなたがdirnamesリストを変更常にであるということですが、これも、ルートレベルにあるすべてのサブディレクトリが削除されていることを意味し、したがって、再帰呼び出しはしないでください様々なProject Xディレクトリにアクセスしてください。

if 'TARGET' in dirnames: 
    dirnames[:] = ['TARGET'] 

これはos.walk呼び出しはProject Xディレクトリを訪問することができますが、Irrelevantの内側に行くから、それを防ぐことができます:あなたが欲しい

は、他のディレクトリTARGET 1が存在しているだけをパージすることですもの。

+0

'TARGET'という名前のサブディレクトリがないため、初期パスが'/root'の場合は何もしません。 – martineau

+1

@martineauはい、それは正しいです。 *ディレクトリ名を他のディレクトリに再帰的に* * *除外することは、答えのポイントです。 – Bakuriu

+0

ああ、右...今すぐ手に入れる。いい答えだ。 – martineau

2

このようなホワイトリストのシナリオでは、glob.iglobを使用してパターンでディレクトリを取得することをお勧めします。これはジェネレーターなので、各結果が見つかるのと同じくらい速く取得できます(注:書面ではos.scandirではなくos.listdirで実装されているので、生成器の半分に過ぎず、各ディレクトリーが熱心にスキャンされ、現在のディレクトリから値を取得すると、次のディレクトリだけをスキャンします)。たとえば、この場合には:

from future_builtins import filter # Only on Py2 to get generator based filter 

import os.path 
import glob 

from operator import methodcaller 

try: 
    from os import scandir  # Built-in on 3.5 and above 
except ImportError: 
    from scandir import scandir # PyPI package on 3.4 and below 

# If on 3.4+, use glob.escape for safety; before then, if path might contain glob 
# special characters and you don't want them processed you need to escape manually 
globpat = os.path.join(glob.escape(path), '*', 'TARGET') 

# Find paths matching the pattern, filtering out non-directories as we go: 
for targetdir in filter(os.path.isdir, glob.iglob(globpat)): 
    # targetdir is the qualified name of a single directory matching the pattern, 
    # so if you want to process the files in that directory, you can follow up with: 
    for fileentry in filter(methodcaller('is_file'), scandir(targetdir)): 
     # fileentry is a DirEntry with attributes for .name, .path, etc. 

は、より高度な使用のためのos.scandir上のドキュメントを参照してください、またはあなただけであるとして、あなたの元のコードの大部分を維持するために内部ループos.walkにコールすることができます。

実際にos.walkを使用する必要がある場合は、dirsのプルーニングのターゲットを絞ることができます。 TARGETディレクトリはすべて1レベル下にする必要があるため、実際はかなり簡単です。 os.walkがデフォルトでトップダウンします。これは、結果の最初のセットがルートディレクトリ(TARGETのエントリのみにプルーニングしたくない)になることを意味します。だから、あなたが行うことができます:

import fnmatch 

for i, (dirpath, dirs, files) in enumerate(os.walk(path)): 
    if i == 0: 
     # Top level dir, prune non-Project dirs 
     dirs[:] = fnmatch.filter(dirs, 'Project *') 
    elif os.path.samefile(os.path.dirname(dirpath), path): 
     # Second level dir, prune non-TARGET dirs 
     dirs[:] = fnmatch.filter(dirs, 'TARGET') 
    else: 
     # Do whatever handling you'd normally do for files and directories 
     # located under path/Project */TARGET/ 
+0

ディレクトリが複数のレベルでネストされていると誤解していますか?そして、これが失敗しなければ、それは ''無関係 'ディレクトリの内容をまだ列挙していることを意味し、内部の各パスについてパターンを検証しないことをチェックしますが、それでもその時間を無駄にしなければなりません。 – Bakuriu

+0

@Bakuriu:2つ以上のレベルにネストされている場合は、 'globpat = os.path.join(glob.escape(path)、 '**'、 'TARGET')'を実行し、 'iglob'呼び出しをglob .iglob(globpat、recursive = True) 'それは無期限に下降します。 OPはそれをちょうど1つ下のレベルにしたいと思われたので、深い再帰は必要ありません。ワイルドカードを微調整して、その単一レベルの場合に「無関係」ディレクトリを避けることもできます。 '' * ''コンポーネントを' 'Project [AB]''に置き換えるか、 '' Project ''プレフィックスを持つディレクトリに対して '' Project * ''を置き換えます。 – ShadowRanger

+0

はい、しかし、私の指摘は、あなたが '**'を使うと答えが非効率になるということです。 'iglob'は'無関係 'の問題の下に* nothing *があることを知ることはできませんが、それでもすべての内容をチェックする必要があります( '無関係'には何百万ものファイルが含まれているか、ネストされたサブディレクトリにかなりの時間がかかります)。 – Bakuriu

関連する問題