web-dev-qa-db-ja.com

Pythonでディレクトリツリー構造をリストしますか?

os.walk()を使用して、ディレクトリ内のすべてのサブディレクトリまたはすべてのファイルを一覧表示できることを知っています。ただし、ディレクトリツリーの完全なコンテンツを一覧表示したいと思います。

- Subdirectory 1:
   - file11
   - file12
   - Sub-sub-directory 11:
         - file111
         - file112
- Subdirectory 2:
    - file21
    - sub-sub-directory 21
    - sub-sub-directory 22    
        - sub-sub-sub-directory 221
            - file 2211

Pythonでこれを最高に達成する方法は?

74
cinny

書式設定でこれを行う関数は次のとおりです。

import os

def list_files(startpath):
    for root, dirs, files in os.walk(startpath):
        level = root.replace(startpath, '').count(os.sep)
        indent = ' ' * 4 * (level)
        print('{}{}/'.format(indent, os.path.basename(root)))
        subindent = ' ' * 4 * (level + 1)
        for f in files:
            print('{}{}'.format(subindent, f))
112
dhobbs

インデントなしのソリューション:

for path, dirs, files in os.walk(given_path):
  print path
  for f in files:
    print f

os.walkは既に、トップダウンで深さ優先の探索を行っています。

Dirsリストを無視すると、言及した重複が防止されます。

18
Intra

私は同じものを探してここに来て、私のためにドブスの答えを使いました。コミュニティに感謝する方法として、akshayが尋ねたように、ファイルに書き込むための引数をいくつか追加し、ファイルを表示することをオプションにしました。また、インデントをオプションの引数にして、変更できるようにしました。2が好きな人もいれば4が好きな人もいます。

異なるループを使用して、ファイルを表示していないループが各反復で必要かどうかをチェックしないようにしました。

ドブスの答えが私を助けてくれたので、それが他の誰かを助けることを願っています。どうもありがとう。

def showFolderTree(path,show_files=False,indentation=2,file_output=False):
"""
Shows the content of a folder in a tree structure.
path -(string)- path of the root folder we want to show.
show_files -(boolean)-  Whether or not we want to see files listed.
                        Defaults to False.
indentation -(int)- Indentation we want to use, defaults to 2.   
file_output -(string)-  Path (including the name) of the file where we want
                        to save the tree.
"""


tree = []

if not show_files:
    for root, dirs, files in os.walk(path):
        level = root.replace(path, '').count(os.sep)
        indent = ' '*indentation*(level)
        tree.append('{}{}/'.format(indent,os.path.basename(root)))

if show_files:
    for root, dirs, files in os.walk(path):
        level = root.replace(path, '').count(os.sep)
        indent = ' '*indentation*(level)
        tree.append('{}{}/'.format(indent,os.path.basename(root)))    
        for f in files:
            subindent=' ' * indentation * (level+1)
            tree.append('{}{}'.format(subindent,f))

if file_output:
    output_file = open(file_output,'w')
    for line in tree:
        output_file.write(line)
        output_file.write('\n')
else:
    # Default behaviour: print on screen.
    for line in tree:
        print line
12
Rubén Cabrera

上記の回答に似ていますが、python3については、間違いなく読み取り可能であり、間違いなく拡張可能です。

from pathlib import Path

class DisplayablePath(object):
    display_filename_prefix_middle = '├──'
    display_filename_prefix_last = '└──'
    display_parent_prefix_middle = '    '
    display_parent_prefix_last = '│   '

    def __init__(self, path, parent_path, is_last):
        self.path = Path(str(path))
        self.parent = parent_path
        self.is_last = is_last
        if self.parent:
            self.depth = self.parent.depth + 1
        else:
            self.depth = 0

    @property
    def displayname(self):
        if self.path.is_dir():
            return self.path.name + '/'
        return self.path.name

    @classmethod
    def make_tree(cls, root, parent=None, is_last=False, criteria=None):
        root = Path(str(root))
        criteria = criteria or cls._default_criteria

        displayable_root = cls(root, parent, is_last)
        yield displayable_root

        children = sorted(list(path
                               for path in root.iterdir()
                               if criteria(path)),
                          key=lambda s: str(s).lower())
        count = 1
        for path in children:
            is_last = count == len(children)
            if path.is_dir():
                yield from cls.make_tree(path,
                                         parent=displayable_root,
                                         is_last=is_last,
                                         criteria=criteria)
            else:
                yield cls(path, displayable_root, is_last)
            count += 1

    @classmethod
    def _default_criteria(cls, path):
        return True

    @property
    def displayname(self):
        if self.path.is_dir():
            return self.path.name + '/'
        return self.path.name

    def displayable(self):
        if self.parent is None:
            return self.displayname

        _filename_prefix = (self.display_filename_prefix_last
                            if self.is_last
                            else self.display_filename_prefix_middle)

        parts = ['{!s} {!s}'.format(_filename_prefix,
                                    self.displayname)]

        parent = self.parent
        while parent and parent.parent is not None:
            parts.append(self.display_parent_prefix_middle
                         if parent.is_last
                         else self.display_parent_prefix_last)
            parent = parent.parent

        return ''.join(reversed(parts))

使用例:

paths = DisplayablePath.make_tree(Path('doc'))
for path in paths:
    print(path.displayable())

出力例:

doc/
├── _static/
│   ├── embedded/
│   │   ├── deep_file
│   │   └── very/
│   │       └── deep/
│   │           └── folder/
│   │               └── very_deep_file
│   └── less_deep_file
├── about.rst
├── conf.py
└── index.rst

ノート

  • これは再帰を使用します。本当にdeepフォルダツリーで RecursionError が発生します。
  • ツリーは遅延評価されます。本当にwideフォルダツリーでうまく動作するはずです。ただし、特定のフォルダーの直接の子は遅延評価されません。

編集:

  • ボーナスを追加しました!パスをフィルタリングするための条件コールバック。
8
abstrus

この素晴らしい投稿に基づいて

http://code.activestate.com/recipes/217212-treepy-graphically-displays-the-directory-structur/

ここでは、まったく同じように動作するように改良されています

http://linux.die.net/man/1/tree

#!/ usr/bin/env python2 
#-*-コーディング:utf-8-*-
 
#tree.py 
 #
#Doug Dahms 
#
#によって書かれたコマンドラインで指定されたパスのツリー構造を印刷します
 
 os import listdir、 sep 
 from os.path import abspath、basename、isdir 
 from sys import argv 
 
 def tree(dir、padding、print_files = False、isLast = False、 isFirst = False):
 if isFirst:
 print padding.decode( 'utf8')[:-1] .encode( 'utf8')+ dir 
 else:
 if isLast:
 print padding.decode( 'utf8')[:-1] .encode( 'utf8')+ '└──' + basename(abspath(dir))
 else:
 print padding.decode( 'utf8')[:-1] .encode( 'utf8')+ '├──' + basename(abspath(dir))
 files = [] 
 if print_files:
 files = listdir(dir)
 else:
 files = [listdir(dir)のxのxはisdir(dir + sep + x)] 
 is not isFirst:
 padding = padding + '' 
 files = Sorted(files、key = lambda s:s.lower())
 count = 0 
 last = len(files) -1 
 for i、列挙型ファイル(files):
 count + = 1 
 path = dir + sep + file 
 isLast = i == last 
 if isdir(path):
 if count == len(files):
 if isFirst:
 tree(path、padding、print_files、isLast、False)
 else:
 tree(path、padding + ''、print_files、isLast、False)
 else:
 tree(path、padding + '│'、print_files、 isLast、False)
 else:
 if isLast:
 print padding + '└──' + file 
 else:
 print padding + ' ├── '+ file 
 
 def usage():
 return' ''使用法:%s [-f] 
指定されたパスのツリー構造を印刷します。 
オプション:
-fファイルとディレクトリを出力します
 PATHプロセスへのパス '' '%basename(argv [0])
 
 def main ():
 if len(argv)== 1:
 print usage()
 Elif len(argv)== 2:
#ディレクトリのみを印刷
 path = argv [1] 
 if isdir(path):
 tree(path、 ''、False、False、True)
 else:
 print 'エラー:\' '+パス+'\'はディレクトリではありません' 
 Elif len(argv)== 3 and argv [1] == '-f':
#ディレクトリとファイルの出力
 path = argv [2] 
 if isdir(path):
 tree(path、 ''、True、False、True)
 else :
 print 'エラー:\' '+パス+'\'はディレクトリではありません' 
 else:
 print usage()
 
 if __ == '__main __':
 main()
 
 
6
albfan
import os

def fs_tree_to_dict(path_):
    file_token = ''
    for root, dirs, files in os.walk(path_):
        tree = {d: fs_tree_to_dict(os.path.join(root, d)) for d in dirs}
        tree.update({f: file_token for f in files})
        return tree  # note we discontinue iteration trough os.walk

誰かが興味があるなら-その再帰関数は辞書のネストされた構造を返します。キーは(ディレクトリとファイルの)file system名で、値は次のいずれかです。

  • ディレクトリのサブ辞書
  • ファイルの文字列(file_tokenを参照)

この例では、ファイルを指定する文字列は空です。それらは、例えば指定されたファイルの内容、その所有者情報、特権、または辞書とは異なるオブジェクト。辞書でない限り、以降の操作で「ディレクトリタイプ」と簡単に区別できます。

ファイルシステムにそのようなツリーがある:

# bash:
$ tree /tmp/ex
/tmp/ex
├── d_a
│   ├── d_a_a
│   ├── d_a_b
│   │   └── f1.txt
│   ├── d_a_c
│   └── fa.txt
├── d_b
│   ├── fb1.txt
│   └── fb2.txt
└── d_c

結果は次のようになります。

# python 2 or 3:
>>> fs_tree_to_dict("/tmp/ex")
{
    'd_a': {
        'd_a_a': {},
        'd_a_b': {
            'f1.txt': ''
        },
        'd_a_c': {},
        'fa.txt': ''
    },
    'd_b': {
        'fb1.txt': '',
        'fb2.txt': ''
    },
    'd_c': {}
}

あなたがそれを好めば、私はすでにこのもの(そしてNice pyfakefsヘルパー)でパッケージ(python 2と3)を作成しました: https://pypi.org/project/fsforge/

4

上記のdhobbsの答えの上に( https://stackoverflow.com/a/9728478/624597 )、ここに結果をファイルに保存する追加の機能があります(私は個人的にそれをコピーして貼り付けるために使用します FreeMind 構造の概要を把握するため、インデントにはスペースではなくタブを使用しました):

import os

def list_files(startpath):

    with open("folder_structure.txt", "w") as f_output:
        for root, dirs, files in os.walk(startpath):
            level = root.replace(startpath, '').count(os.sep)
            indent = '\t' * 1 * (level)
            output_string = '{}{}/'.format(indent, os.path.basename(root))
            print(output_string)
            f_output.write(output_string + '\n')
            subindent = '\t' * 1 * (level + 1)
            for f in files:
                output_string = '{}{}'.format(subindent, f)
                print(output_string)
                f_output.write(output_string + '\n')

list_files(".")
3
ellockie

Linux Shellの「tree」コマンドを実行できます。

インストール:

   ~$Sudo apt install tree

Pythonで使用する

    >>> import os
    >>> os.system('tree <desired path>')

例:

    >>> os.system('tree ~/Desktop/myproject')

これにより、構造が簡潔になり、視覚的により包括的で入力しやすくなります。

2

このソリューションは、システムにtreeがインストールされている場合にのみ機能します。ただし、他の人の助けになる場合に備えて、このソリューションをここに残しています。

ツリーにXML(tree -X)またはJSON(tree -J)としてツリー構造を出力するように指示できます。もちろん、JSONはpythonで直接解析でき、XMLはlxmlで簡単に読み取ることができます。

例として次のディレクトリ構造を使用します。

[sri@localhost Projects]$ tree --charset=ascii bands
bands
|-- DreamTroll
|   |-- MattBaldwinson
|   |-- members.txt
|   |-- PaulCarter
|   |-- SimonBlakelock
|   `-- Rob Stringer
|-- KingsX
|   |-- DougPinnick
|   |-- JerryGaskill
|   |-- members.txt
|   `-- TyTabor
|-- Megadeth
|   |-- DaveMustaine
|   |-- DavidEllefson
|   |-- DirkVerbeuren
|   |-- KikoLoureiro
|   `-- members.txt
|-- Nightwish
|   |-- EmppuVuorinen
|   |-- FloorJansen
|   |-- JukkaNevalainen
|   |-- MarcoHietala
|   |-- members.txt
|   |-- TroyDonockley
|   `-- TuomasHolopainen
`-- Rush
    |-- AlexLifeson
    |-- GeddyLee
    `-- NeilPeart

5 directories, 25 files

XML

<?xml version="1.0" encoding="UTF-8"?>
<tree>
  <directory name="bands">
    <directory name="DreamTroll">
      <file name="MattBaldwinson"></file>
      <file name="members.txt"></file>
      <file name="PaulCarter"></file>
      <file name="RobStringer"></file>
      <file name="SimonBlakelock"></file>
    </directory>
    <directory name="KingsX">
      <file name="DougPinnick"></file>
      <file name="JerryGaskill"></file>
      <file name="members.txt"></file>
      <file name="TyTabor"></file>
    </directory>
    <directory name="Megadeth">
      <file name="DaveMustaine"></file>
      <file name="DavidEllefson"></file>
      <file name="DirkVerbeuren"></file>
      <file name="KikoLoureiro"></file>
      <file name="members.txt"></file>
    </directory>
    <directory name="Nightwish">
      <file name="EmppuVuorinen"></file>
      <file name="FloorJansen"></file>
      <file name="JukkaNevalainen"></file>
      <file name="MarcoHietala"></file>
      <file name="members.txt"></file>
      <file name="TroyDonockley"></file>
      <file name="TuomasHolopainen"></file>
    </directory>
    <directory name="Rush">
      <file name="AlexLifeson"></file>
      <file name="GeddyLee"></file>
      <file name="NeilPeart"></file>
    </directory>
  </directory>
  <report>
    <directories>5</directories>
    <files>25</files>
  </report>
</tree>

JSON

[sri@localhost Projects]$ tree -J bands
[
  {"type":"directory","name":"bands","contents":[
    {"type":"directory","name":"DreamTroll","contents":[
      {"type":"file","name":"MattBaldwinson"},
      {"type":"file","name":"members.txt"},
      {"type":"file","name":"PaulCarter"},
      {"type":"file","name":"RobStringer"},
      {"type":"file","name":"SimonBlakelock"}
    ]},
    {"type":"directory","name":"KingsX","contents":[
      {"type":"file","name":"DougPinnick"},
      {"type":"file","name":"JerryGaskill"},
      {"type":"file","name":"members.txt"},
      {"type":"file","name":"TyTabor"}
    ]},
    {"type":"directory","name":"Megadeth","contents":[
      {"type":"file","name":"DaveMustaine"},
      {"type":"file","name":"DavidEllefson"},
      {"type":"file","name":"DirkVerbeuren"},
      {"type":"file","name":"KikoLoureiro"},
      {"type":"file","name":"members.txt"}
    ]},
    {"type":"directory","name":"Nightwish","contents":[
      {"type":"file","name":"EmppuVuorinen"},
      {"type":"file","name":"FloorJansen"},
      {"type":"file","name":"JukkaNevalainen"},
      {"type":"file","name":"MarcoHietala"},
      {"type":"file","name":"members.txt"},
      {"type":"file","name":"TroyDonockley"},
      {"type":"file","name":"TuomasHolopainen"}
    ]},
    {"type":"directory","name":"Rush","contents":[
      {"type":"file","name":"AlexLifeson"},
      {"type":"file","name":"GeddyLee"},
      {"type":"file","name":"NeilPeart"}
    ]}
  ]},
  {"type":"report","directories":5,"files":25}
]
1
shrewmouse

@ellockieよりも高速かもしれません(たぶん)

 import os 
 def file_writer(text):
 with open( "folder_structure.txt"、 "a")as f_output:
 f_output.write(text) 
 def list_files(startpath):
 
 
 root、dirs、os.walk(startpath)内のファイル:
 level = root.replace (startpath、 '').count(os.sep)
 indent = '\ t' * 1 *(レベル)
 output_string = '{} {}/\ n'.format(indent 、os.path.basename(root))
 file_writer(output_string)
 subindent = '\ t' * 1 *(level + 1)
 output_string = '%s%s\n '%(subindent、[f in f in files])
 file_writer(' '。join(output_string))
 
 
 list_files( "/" )
 

以下のスクリーンショットのテスト結果:

enter image description here

1
Enes ERGUN

ここでは、次のような出力のコードを見つけることができます。 https://stackoverflow.com/a/56622847/66713

V .
|-> V folder1
|   |-> V folder2
|   |   |-> V folder3
|   |   |   |-> file3.txt
|   |   |-> file2.txt
|   |-> V folderX
|   |-> file1.txt
|-> 02-hw1_wdwwfm.py
|-> 06-t1-home1.py
|-> 06-t1-home2.py
|-> hw1.py
0
Igor Z

まだ答えを探している人のために。辞書のパスを取得する再帰的なアプローチを次に示します。

import os


def list_files(startpath):
    for root, dirs, files in os.walk(startpath):
        dir_content = []
        for dir in dirs:
            go_inside = os.path.join(startpath, dir)
            dir_content.append(list_files(go_inside))
        files_lst = []
        for f in files:
            files_lst.append(f)
        return {'name': root, 'files': files_lst, 'dirs': dir_content}
0
sky