แสดงรายการโครงสร้างไดเร็กทอรีใน python?


114

ฉันรู้ว่าเราสามารถใช้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

คำตอบ:


150

นี่คือฟังก์ชั่นในการจัดรูปแบบ:

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

1
สิ่งนี้ได้ผลดีมากขอบคุณ แม้ว่าคนส่วนใหญ่จะรู้ แต่ก็ยังคงเป็นประโยชน์สำหรับผู้มาใหม่ใน python - โปรดทราบว่าคุณจะต้องเรียกใช้ฟังก์ชันในตอนท้าย (สมมติว่าเป็น windows) ดังนั้นคุณอาจเพิ่มบรรทัดใหม่ต่อท้ายด้วย content list_files ("D: \\ ")
ราหุล

1
ทำงานได้ดีกับ python3 แต่ใน python2 ValueError: zero length field name in formatถูกโยนทิ้ง
nipunasudha

3
ถ้า startpath ซ้ำภายใน root มันจะไม่แทนที่แต่ละเหตุการณ์ใช่หรือไม่ การเปลี่ยนroot.replace(startpath, '', 1)ควรแก้ไข
drone.ah

34

คล้ายกับคำตอบข้างต้น แต่สำหรับ 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บนต้นไม้โฟลเดอร์ที่ลึกมาก
  • ต้นไม้ถูกประเมินอย่างเกียจคร้าน ควรทำงานได้ดีบนต้นไม้โฟลเดอร์ที่กว้างมาก เด็กในทันทีของโฟลเดอร์ที่กำหนดจะไม่ได้รับการประเมินอย่างเฉื่อยชา

แก้ไข:

  • เพิ่มโบนัส! เกณฑ์การเรียกกลับสำหรับการกรองเส้นทาง

เครื่องมือที่ดีคุณมีตัวอย่างสั้น ๆ เกี่ยวกับวิธีใช้เกณฑ์เพื่อยกเว้นชื่อโฟลเดอร์หรือไม่?
Matt-Mac-Muffin

นี่คือสิ่งที่ฉันกำลังมองหา ขอบคุณมาก!
dheinz

24

วิธีแก้ปัญหาโดยไม่มีการเยื้องของคุณ:

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

os.walk เดินจากบนลงล่างเชิงลึกก่อนที่คุณกำลังมองหาอยู่แล้ว

การละเว้นรายชื่อ dirs จะป้องกันการทับซ้อนที่คุณพูดถึง


2
python พูดว่า:NameError: name 'path' is not defined
Francesco Mantovani

1
@FrancescoMantovani "path" เป็นตัวแปรที่มีไดเร็กทอรีที่คุณต้องการพิมพ์เช่น r "C: \ Users \ username \ Documents \ path"
zwelz

17

แสดงรายการโครงสร้างไดเร็กทอรีใน Python?

เรามักจะชอบใช้ GNU tree แต่เราไม่ได้มี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

เริ่มต้นด้วยการใช้ตัวอย่างที่

  • ใช้PathวัตถุPython 3
  • ใช้นิพจน์yieldและyield 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สำหรับการวนซ้ำแบบวนซ้ำได้ แต่ต้องมีการเขียนซ้ำ เรายังสามารถใช้itertools.teeแทนการสร้างรายการเนื้อหาไดเร็กทอรี แต่อาจมีการแลกเปลี่ยนเชิงลบและอาจทำให้โค้ดซับซ้อนยิ่งขึ้น

ยินดีต้อนรับความคิดเห็น!


หากต้องการพิมพ์บรรทัดของโค้ดหลังจากelif not limit_to_directories:เพิ่มสิ่งต่อไปนี้: info = prefix + pointer + path.name; try: with path.open('r') as f: n_lines = len(f.readlines()); loc = f' LOC: {n_lines}'; info += loc; except UnicodeDecodeError: pass; yield info ดูลิงก์นี้สำหรับช่องว่างที่เหมาะสม
Steven C. Howell

นี่คือสิ่งที่ฉันต้องการในโค้ดของฉันและสอนเทคนิค Python ใหม่ ๆ ให้ฉัน! สิ่งเดียวที่ฉันทราบคือcontentsต้องกรองหากlimit_to_directoriesเป็นจริง มิฉะนั้นถ้าโฟลเดอร์ไม่มีไดเร็กทอรีสำหรับไฟล์สุดท้ายต้นไม้จะไม่ถูกวาดอย่างถูกต้อง if limit_to_directories: contents = [path for path in contents if path.is_dir()]
hennign

@hennign ขอบคุณอัปเดตคำตอบขอขอบคุณข้อเสนอแนะ
แอรอนฮอลล์

Python ทั้งหมดถูกกำหนดไว้ล่วงหน้าในการlist(dir_path.iterdir())ส่งคืนโครงสร้างไดเรกทอรีจากบนลงล่างที่เรียงลำดับอย่างถูกต้อง ผมเห็นไม่มีการรับประกันดังกล่าวในAPI สำหรับ iterdir () โปรดระบุข้อมูลอ้างอิงเกี่ยวกับวิธีการiterdir()สั่งซื้อหรือการรับประกันว่าจะให้คำสั่งซื้อที่ต้องการได้อย่างไร
นี่

@ingyhere ฉันไม่แน่ใจว่าคุณได้แนวคิดนั้นมาจากไหน - ดูเหมือนว่าจะใช้os.listdir()โดยค่าเริ่มต้น - ซึ่งไม่รับประกันคำสั่งซื้อ : "รายการเป็นไปตามลำดับโดยพลการและไม่รวมรายการพิเศษ '' และ ".. " แม้ว่าจะมีอยู่ในไดเร็กทอรีก็ตาม "
Aaron Hall

15

ฉันมาที่นี่เพื่อมองหาสิ่งเดียวกันและใช้คำตอบ 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

ฉันรู้สึกว่าคำตอบนี้ไม่ได้มีส่วนช่วยในคำตอบที่ยอมรับแล้ว สิ่งเดียวที่คุณให้คือรหัสปุยเพิ่มเติมเพื่อปิดคุณสมบัติหรือไม่ในการตอบกลับ
CodeLikeBeaker

3
ความรู้สึกของคุณใช่ @ jason-heine คำตอบที่ได้รับการยอมรับนั้นดีพอ แต่บางคนถามว่าจะทำอย่างไรให้ขนปุยนี้และฉันอยากจะให้อะไรกับพวกเขา ลงคะแนนหรือรายงานคำตอบของฉันหากคุณไม่ต้องการเห็นสิ่งนี้ใน SO ฉันคิดว่ามันจะไม่เจ็บ แต่ฉันอาจจะคิดผิด
Rubén Cabrera

3
มันมีประโยชน์แน่นอน ขอบคุณมาก. ฉันใช้มันตามที่เป็นอยู่
vladblindu

7

จากโพสต์ที่ยอดเยี่ยมนี้

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 นำเข้าlistdir , กันยายน
 จากระบบปฏิบัติการ พา ธนำเข้าabspath , basename , isdir
 จากsys import argv

def ต้นไม้( dir , padding , print_files = เท็จ, isLast = เท็จ, isFirst = เท็จ): ถ้าisFirst : พิมพ์padding ถอดรหัส( 'utf8' ) [: - 1 ] เข้ารหัส( 'utf8' ) + dir
     อื่น: ถ้าisLast : พิมพ์padding ถอดรหัส( 'utf8' ) [: - 1 เข้ารหัส
    
         
        
             ]( 'utf8' ) + '└──' + basename ( abspath ( dir )) อื่น ๆ: พิมพ์padding ถอดรหัส( 'utf8' ) [: - 1 ] เข้ารหัส( 'utf8' ) + '├──' + basename ( abspath ( dir )) 
    ไฟล์= [] ถ้าprint_files : 
        files = listdir ( dir ) 
        ไฟล์อื่น   
        
                
    
     : = [ x สำหรับx ในlistdir ( ผบ) ถ้าisdir ( dir + กันยายน+ x )] ถ้าไม่isFirst : 
        padding = padding + '' 
    ไฟล์= เรียง( ไฟล์, คีย์= แลมบ์ดาs : s . ลดลง()) 
    นับ= 0 
    สุดท้าย= len (  
       ไฟล์) - + ไฟล์  1 สำหรับi , file in enumerate ( files ): 
        count + = 1 
        path = dir + sep
     
        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 , เท็จ)
            
                 
                  
            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      Print files as well as directories
PATH    Path to process''' % basename(argv[0])

def main():
    if len(argv) == 1:
        print usage()
    elif len(argv) == 2:
        # print just directories
        path = argv[1]
        if isdir(path):
            tree(path, '', False, False, True)
        else:
            print 'ERROR: \'' + path + '\' is not a directory'
    elif len(argv) == 3 and argv[1] == '-f':
        # print directories and files
        path = argv[2]
        if isdir(path):
            tree(path, '', True, False, True)
        else:
            print 'ERROR: \'' + path + '\' ไม่ใช่ไดเร็กทอรี ' else : print Usage ()
    
        

ถ้า__name__ == '__main__' : 
    main () 


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

ถ้าคุณชอบฉันได้สร้างแพ็คเกจ (python 2 & 3) ด้วยสิ่งนี้แล้ว (และpyfakefsผู้ช่วยที่ดี): 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(".")

2

คุณสามารถรันคำสั่ง 'tree' ของ Linux shell ได้

การติดตั้ง:

   ~$sudo apt install tree

ใช้ใน python

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

ตัวอย่าง:

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

สิ่งนี้ช่วยให้คุณมีโครงสร้างที่สะอาดขึ้นและมองเห็นได้ครอบคลุมมากขึ้นและพิมพ์ได้ง่าย


นี่ไม่ใช่โซลูชันแบบพกพามากนักเนื่องจากสิ่งนี้ล้มเหลวใน Windows + ต้องอาศัยโปรแกรมเพิ่มเติม
oglop

2

วิธีนี้จะใช้ได้ผลก็ต่อเมื่อคุณtreeติดตั้งบนระบบของคุณ อย่างไรก็ตามฉันจะทิ้งโซลูชันนี้ไว้ที่นี่เผื่อว่าจะช่วยคนอื่นได้

คุณสามารถบอกให้ทรีส่งออกโครงสร้างทรีเป็น XML ( tree -X) หรือ JSON ( tree -J) JSON แน่นอนสามารถแยกวิเคราะห์โดยตรงกับงูหลามและ 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

อาจเร็วกว่า @ellockie (อาจจะ)

นำเข้าระบบปฏิบัติการ
def file_writer (ข้อความ):
    โดยเปิด ("folder_structure.txt", "a") เป็น f_output:
        f_output.write (ข้อความ)
def list_files (เส้นทางเริ่มต้น):


    สำหรับ root, dirs, ไฟล์ใน os.walk (startpath):
        ระดับ = root.replace (startpath, '') .count (os.sep)
        เยื้อง = '\ t' * 1 * (ระดับ)
        output_string = '{} {} / \ n'.format (เยื้อง os.path.basename (root))
        file_writer (เอาต์พุต _ สตริง)
        subindent = '\ t' * 1 * (ระดับ + 1)
        output_string = '% s% s \ n'% (subindent, [f สำหรับ f ในไฟล์])
        file_writer (". join (output_string))


list_files ("/")

ผลการทดสอบในภาพหน้าจอด้านล่าง:

ป้อนคำอธิบายภาพที่นี่



0

สำหรับใครที่ยังหาคำตอบ. นี่คือวิธีการเรียกซ้ำเพื่อรับเส้นทางในพจนานุกรม

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

คำตอบของ @ dhobbsเยี่ยมมาก!

แต่เพียงแค่เปลี่ยนเป็นเรื่องง่ายในการรับข้อมูลระดับ

def print_list_dir(dir):
    print("=" * 64)
    print("[PRINT LIST DIR] %s" % dir)
    print("=" * 64)
    for root, dirs, files in os.walk(dir):
        level = root.replace(dir, '').count(os.sep)
        indent = '| ' * level
        print('{}{} \\'.format(indent, os.path.basename(root)))
        subindent = '| ' * (level + 1)
        for f in files:
            print('{}{}'.format(subindent, f))
    print("=" * 64)

และผลลัพธ์เช่น

================================================================
[PRINT LIST DIR] ./
================================================================
 \
| os_name.py
| json_loads.py
| linspace_python.py
| list_file.py
| to_gson_format.py
| type_convert_test.py
| in_and_replace_test.py
| online_log.py
| padding_and_clipping.py
| str_tuple.py
| set_test.py
| script_name.py
| word_count.py
| get14.py
| np_test2.py
================================================================

คุณจะได้รับระดับโดยการ|นับ!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.