Development Tip

파이썬에서 디렉토리 트리 구조를 나열합니까?

yourdevel 2020. 10. 11. 11:28
반응형

파이썬에서 디렉토리 트리 구조를 나열합니까?


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

들여 쓰기가없는 솔루션 :

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

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

dirs 목록을 무시하면 겹치는 것을 방지 할 수 있습니다.


나는 똑같은 것을 찾고 여기에 와서 나를 위해 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

위의 답변과 유사하지만 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 가 발생 합니다.
  • 나무는 느리게 평가됩니다. 정말 넓은 폴더 트리 에서 잘 작동해야합니다 . 그러나 주어진 폴더의 직계 자식은 느리게 평가되지 않습니다.

편집하다:

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

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

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

여기에 정확히 다음과 같이 작동하는 개선이 있습니다.

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

#!/usr/bin/env python2
# -*- coding: utf-8 -*-

# tree.py
#
# Written by Doug Dahms
#
# Prints the tree structure for the path specified on the command line

from 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 = [x for x in listdir(dir) if isdir(dir + sep + x)]
    if not isFirst:
        padding = padding + '   '
    files = sorted(files, key=lambda s: s.lower())
    count = 0
    last = len(files) - 1
    for i, file in enumerate(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 '''Usage: %s [-f] 
Print tree structure of path specified.
Options:
-f 파일 및 디렉토리 인쇄
프로세스 경로 '' '% basename (argv [0])

def main () :
    len (argv) == 1 :
        인쇄 사용 ()
    elif len (argv) == 2 :
        # 디렉토리 만 인쇄
        경로 = argv [1]
        isdir (경로) :
            트리 (경로, '', False, False, True)
        그밖에:
            print '오류 : \'+ 경로 + '\'는 디렉토리가 아닙니다. '
    elif len (argv) == 3 및 argv [1] == '-f':
        # 인쇄 디렉토리 및 파일
        경로 = argv [2]
        isdir (경로) :
            트리 (경로, '', True, False, True)
        그밖에:
            print '오류 : \'+ 경로 + '\'는 디렉토리가 아닙니다. '
    그밖에:
        인쇄 사용 ()

__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/


위의 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(".")

Linux 쉘의 '트리'명령을 실행할 수 있습니다.

설치:

   ~$sudo apt install tree

파이썬에서 사용

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

예:

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

이것은 더 깔끔한 구조를 제공하고 시각적으로 더 포괄적이고 입력하기 쉽습니다.


@ellockie보다 빠를 수도 있습니다 (아마도)

수입 OS
def file_writer (텍스트) :
    open ( "folder_structure.txt", "a")를 f_output으로 사용 :
        f_output.write (텍스트)
def list_files (startpath) :


    root, dirs, os.walk (startpath)의 파일 :
        레벨 = root.replace (startpath, '') .count (os.sep)
        들여 쓰기 = '\ t'* 1 * (레벨)
        output_string = '{} {} / \ n'.format (indent, os.path.basename (root))
        파일 _ 작성기 (출력 _ 문자열)
        subindent = '\ t'* 1 * (레벨 + 1)
        output_string = '% s % s \ n'% (subindent, [f for f in files])
        file_writer ( ''. join (출력 _ 문자열))


목록 _ 파일 ( "/")

아래 스크린 샷의 테스트 결과 :

여기에 이미지 설명 입력


이 솔루션은 tree시스템에 설치 한 경우에만 작동합니다 . 그러나 다른 사람을 도울 경우를 대비 하여이 솔루션을 여기에 남겨 둡니다.

트리 구조를 XML ( tree -X) 또는 JSON ( tree -J) 으로 출력하도록 tree에 지시 할 수 있습니다 . 물론 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}
]

다음과 같은 출력이있는 코드를 찾을 수 있습니다. https://stackoverflow.com/a/56622847/6671330

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

여전히 답을 찾고있는 사람들을 위해. 다음은 사전에서 경로를 가져 오는 재귀 적 접근 방식입니다.

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}

참고 URL : https://stackoverflow.com/questions/9727673/list-directory-tree-structure-in-python

반응형