[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

파이썬에서 이것을 가장 잘 달성하는 방법은 무엇입니까?



답변

다음은 서식을 지정하는 기능입니다.

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))


답변

위의 답변과 비슷하지만 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

노트

  • 이것은 재귀를 사용합니다. 정말 깊은 폴더 트리 에서 RecursionError 가 발생 합니다.
  • 나무는 느리게 평가됩니다. 정말 넓은 폴더 트리 에서 잘 작동해야합니다 . 그러나 주어진 폴더의 직계 자식은 느리게 평가되지 않습니다.

편집하다:

  • 보너스 추가! 필터링 경로에 대한 기준 콜백.

답변

들여 쓰기가없는 솔루션 :

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

os.walk는 이미 찾고있는 하향식 깊이 우선 걷기를 수행합니다.

dirs 목록을 무시하면 언급 한 중복을 방지 할 수 있습니다.


답변

Python에서 디렉토리 트리 구조를 나열 하시겠습니까?

우리는 일반적으로 GNU 트리 만 사용하는 것을 선호하지만 항상 tree모든 시스템에 있는 것은 아니며 때때로 Python 3을 사용할 수 있습니다. 여기에 좋은 대답은 쉽게 복사하여 붙여 넣을 수 있으며 GNU tree를 요구 사항으로 만들지 않습니다 .

tree의 출력은 다음과 같습니다.

$ tree
.
├── package
   ├── __init__.py
   ├── __main__.py
   ├── subpackage
      ├── __init__.py
      ├── __main__.py
      └── module.py
   └── subpackage2
       ├── __init__.py
       ├── __main__.py
       └── module2.py
└── package2
    └── __init__.py

4 directories, 9 files

내가 호출하는 디렉토리 아래의 홈 디렉토리에 위의 디렉토리 구조를 만들었습니다 pyscratch.

나는 또한 그런 종류의 출력에 접근하는 다른 답변을 여기에서 볼 수 있지만 더 간단하고 현대적인 코드와 느리게 평가하는 접근 방식으로 더 잘할 수 있다고 생각합니다.

Python의 트리

먼저 다음과 같은 예를 사용하겠습니다.

  • Python 3 Path객체를 사용 합니다.
  • (생성기 함수를 만드는) yieldyield from표현식을 사용합니다.
  • 우아한 단순성을 위해 재귀를 사용합니다.
  • 추가 명확성을 위해 주석 및 일부 유형 주석을 사용합니다.
from pathlib import Path

# prefix components:
space =  '    '
branch = '│   '
# pointers:
tee =    '├── '
last =   '└── '


def tree(dir_path: Path, prefix: str=''):
    """A recursive generator, given a directory Path object
    will yield a visual tree structure line by line
    with each line prefixed by the same characters
    """    
    contents = list(dir_path.iterdir())
    # contents each get pointers that are ├── with a final └── :
    pointers = [tee] * (len(contents) - 1) + [last]
    for pointer, path in zip(pointers, contents):
        yield prefix + pointer + path.name
        if path.is_dir(): # extend the prefix and recurse:
            extension = branch if pointer == tee else space 
            # i.e. space because last, └── , above so no more |
            yield from tree(path, prefix=prefix+extension)

그리고 지금:

for line in tree(Path.home() / 'pyscratch'):
    print(line)

인쇄물:

├── package
   ├── __init__.py
   ├── __main__.py
   ├── subpackage
      ├── __init__.py
      ├── __main__.py
      └── module.py
   └── subpackage2
       ├── __init__.py
       ├── __main__.py
       └── module2.py
└── package2
    └── __init__.py

얼마나 긴지 알아야하기 때문에 각 디렉토리를 목록으로 구체화해야하지만 나중에 목록을 버립니다. 깊고 광범위한 재귀의 경우 이것은 충분히 게 으르어야합니다.

주석과 함께 위의 코드는 우리가 여기서 무엇을하고 있는지 완전히 이해하기에 충분해야하지만, 필요하다면 디버거를 사용하여 더 잘 이해할 수 있습니다.

더 많은 기능

이제 GNU tree는이 기능에 대해 갖고 싶은 몇 가지 유용한 기능을 제공합니다.

  • 제목 디렉토리 이름을 먼저 인쇄합니다 (자동으로 수행하지만 우리는 인쇄하지 않음).
  • 카운트를 인쇄합니다 n directories, m files
  • 재귀를 제한하는 옵션, -L level
  • 디렉토리로만 제한하는 옵션, -d

또한, 거대한 나무가있을 때, islice텍스트로 인터프리터를 잠그는 것을 피하기 위해 반복을 제한하는 것이 유용합니다. 기본적으로이 값을 임의로 높게 설정할 수 있습니다 1000.

따라서 이전 주석을 제거하고이 기능을 작성해 보겠습니다.

from pathlib import Path
from itertools import islice

space =  '    '
branch = '│   '
tee =    '├── '
last =   '└── '
def tree(dir_path: Path, level: int=-1, limit_to_directories: bool=False,
         length_limit: int=1000):
    """Given a directory Path object print a visual tree structure"""
    dir_path = Path(dir_path) # accept string coerceable to Path
    files = 0
    directories = 0
    def inner(dir_path: Path, prefix: str='', level=-1):
        nonlocal files, directories
        if not level: 
            return # 0, stop iterating
        if limit_to_directories:
            contents = [d for d in dir_path.iterdir() if d.is_dir()]
        else: 
            contents = list(dir_path.iterdir())
        pointers = [tee] * (len(contents) - 1) + [last]
        for pointer, path in zip(pointers, contents):
            if path.is_dir():
                yield prefix + pointer + path.name
                directories += 1
                extension = branch if pointer == tee else space 
                yield from inner(path, prefix=prefix+extension, level=level-1)
            elif not limit_to_directories:
                yield prefix + pointer + path.name
                files += 1
    print(dir_path.name)
    iterator = inner(dir_path, level=level)
    for line in islice(iterator, length_limit):
        print(line)
    if next(iterator, None):
        print(f'... length_limit, {length_limit}, reached, counted:')
    print(f'\n{directories} directories' + (f', {files} files' if files else ''))

이제 다음과 같은 출력을 얻을 수 있습니다 tree.

tree(Path.home() / 'pyscratch')

인쇄물:

pyscratch
├── package
   ├── __init__.py
   ├── __main__.py
   ├── subpackage
      ├── __init__.py
      ├── __main__.py
      └── module.py
   └── subpackage2
       ├── __init__.py
       ├── __main__.py
       └── module2.py
└── package2
    └── __init__.py

4 directories, 9 files

그리고 우리는 수준으로 제한 할 수 있습니다.

tree(Path.home() / 'pyscratch', level=2)

인쇄물:

pyscratch
├── package
   ├── __init__.py
   ├── __main__.py
   ├── subpackage
   └── subpackage2
└── package2
    └── __init__.py

4 directories, 3 files

그리고 출력을 디렉토리로 제한 할 수 있습니다.

tree(Path.home() / 'pyscratch', level=2, limit_to_directories=True)

인쇄물:

pyscratch
├── package
   ├── subpackage
   └── subpackage2
└── package2

4 directories

회고전

돌이켜 보면 path.glob매칭에 사용할 수있었습니다 . path.rglob재귀 적 globbing 에도 사용할 수 있지만 다시 작성해야합니다. itertools.tee디렉토리 내용 목록을 구체화하는 대신 사용할 수도 있지만 이는 부정적인 절충안을 가질 수 있으며 아마도 코드를 더욱 복잡하게 만들 것입니다.

의견을 환영합니다!


답변

나는 똑같은 것을 찾고 여기에 와서 나를 위해 dhobbs 대답을 사용했습니다. 커뮤니티에 감사를 표하는 방법으로, akshay가 요청한대로 파일에 쓰기위한 몇 가지 인수를 추가하고 파일 표시를 선택 사항으로 설정하여 출력이 그렇게되지 않도록했습니다. 또한 일부는 2를 선호하고 다른 일부는 4를 선호하므로 들여 쓰기를 선택적 인수로 만들었습니다.

다른 루프를 사용했기 때문에 파일을 표시하지 않는 루프는 반복 할 때마다 확인하지 않습니다.

dhobbs 답변이 나를 도왔으므로 다른 사람에게 도움이되기를 바랍니다. 감사합니다.

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


답변

이 환상적인 게시물을 기반으로

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-*-#-*-코딩 : utf-8-*-

# tree.py# tree.py
##
# Doug Dahms 작성# Doug Dahms 작성
##
# 명령 줄에 지정된 경로에 대한 트리 구조를 인쇄합니다.# 명령 줄에 지정된 경로에 대한 트리 구조를 인쇄합니다.

os import listdir, sep에서에서 운영 체제 수입 은 listDir , 9월
os.path에서 가져 오기 abspath, basename, isdir에서 운영 체제 . 경로 가져 오기 abspath , basename , isdir
sys import argv에서에서 SYS 수입 ARGV

def tree (dir, padding, print_files = False, isLast = False, isFirst = False) :def 트리 ( dir , padding , print_files = False , isLast = False , isFirst = False ) :
    isFirst 인 경우 :isFirst 인 경우 :
        print padding.decode ( 'utf8') [:-1] .encode ( 'utf8') + dir인쇄 패딩 . 디코드 ( 'utf8' ) [: -1 ]. 인코딩 ( 'utf8' ) + dir 
    그밖에:그렇지 않으면 :
        isLast 인 경우 :isLast 인 경우 :
            print padding.decode ( 'utf8') [:-1] .encode ( 'utf8') + '└──'+ basename (abspath (dir))인쇄 패딩 . 디코드 ( 'utf8' ) [: -1 ]. encode ( 'utf8' ) + '└──' + basename ( abspath ( dir ))   
        그밖에:그렇지 않으면 :
            print padding.decode ( 'utf8') [:-1] .encode ( 'utf8') + '├──'+ basename (abspath (dir))인쇄 패딩 . 디코드 ( 'utf8' ) [: -1 ]. encode ( 'utf8' ) + '├──' + basename ( abspath ( dir ))   
    파일 = []= [] 
    print_files 인 경우 :print_files 인 경우 :
        파일 = listdir (dir)= listdir ( dir )
    그밖에:그렇지 않으면 :
        files = [x for x in listdir (dir) if isdir (dir + sep + x)]= [ x for x in listdir ( dir ) if isdir ( dir + sep + x )]  
    isFirst가 아닌 경우 :isFirst 아닌 경우 : 
        padding = padding + ''= 패딩 + '' 
    files = sorted (files, key = lambda s : s.lower ())= 정렬 됨 ( 파일 , = 람다 s : s . 더 낮은 ())
    개수 = 0= 0 
    마지막 = len (파일)-1= ( 파일 ) - 1  
    i의 경우 enumerate (files)의 파일 :에 대한 , 파일 열거 ( 파일 ) :
        카운트 + = 1+ = 1 
        경로 = dir + sep + 파일= dir + sep + 파일
        isLast = i == 마지막= 나는 == 마지막
        isdir (경로) :경우 ISDIR ( 경로 ) :
            개수 == len (파일) :만약 카운트 == ( 파일 ) :
                isFirst 인 경우 :if isFirst:
                    트리 (경로, 패딩, print_files, isLast, False)(path, padding, print_files, isLast, False)
                그밖에:else:
                    트리 (경로, 패딩 + '', print_files, isLast, False)(path, padding + ' ', print_files, isLast, False)
            그밖에:else:
                tree (경로, 패딩 + '│', print_files, isLast, False)(path, padding + '│', print_files, isLast, False)
        그밖에:else:
            isLast 인 경우 :if isLast:
                print padding + '└──'+ 파일print padding + '└── ' + file
            그밖에:else:
                print padding + '├──'+ 파일print padding + '├── ' + file

def usage () :def usage():
    return '' '사용법 : % s [-f] return '''Usage: %s [-f] 
지정된 경로의 트리 구조를 인쇄합니다.
옵션 :
-f 파일 및 디렉토리 인쇄
프로세스 경로 '' '% basename (argv [0]) % basename(argv[0])

def main () :def main():
    len (argv) == 1 :if len(argv) == 1:
        인쇄 사용 ()print usage()
    elif len (argv) == 2 :elif len(argv) == 2:
        # 디렉토리 만 인쇄# print just directories
        경로 = argv [1]= argv[1]
        isdir (경로) :if isdir(path):
            트리 (경로, '', False, False, True)(path, '', False, False, True)
        그밖에:else:
            print '오류 : \'+ 경로 + '\'는 디렉토리가 아닙니다. 'print 'ERROR: \'' + path + '\' is not a directory'
    elif len (argv) == 3 및 argv [1] == '-f':elif len(argv) == 3 and argv[1] == '-f':
        # 인쇄 디렉토리 및 파일# print directories and files
        경로 = argv [2]= argv[2]
        isdir (경로) :if isdir(path):
            트리 (경로, '', True, False, True)(path, '', True, False, True)
        그밖에:else:
            print '오류 : \'+ 경로 + '\'는 디렉토리가 아닙니다. 'print 'ERROR: \'' + path + '\' is not a directory'
    그밖에:else:
        인쇄 사용 ()인쇄 사용량 ()

__name__ == '__main__'인 경우 :경우 __name__ == '__main__' : 
    본관()()



답변

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)

이 예에서는 파일을 지정하는 문자열이 비어 있습니다. 또한 예를 들어 주어진 파일 내용이나 소유자 정보 또는 권한 또는 dict와 다른 객체가 될 수 있습니다. 사전이 아니면 추가 작업에서 “디렉토리 유형”과 쉽게 구별 할 수 있습니다.

파일 시스템에 이러한 트리가있는 경우 :

# 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': {}
}

당신이 그것을 좋아한다면, 나는 이미이 물건 (그리고 멋진 pyfakefs도우미) 으로 패키지 (파이썬 2 & 3)를 만들었다 :
https://pypi.org/project/fsforge/