簡體   English   中英

Python 2.7-使用scandir遍歷所有子目錄並返回列表

[英]Python 2.7 - Using scandir to traverse all sub-directories and return list

使用Python 2.7和scandir,我需要遍歷所有目錄和子目錄並僅返回目錄列表。 不是文件。 沿路徑的子目錄的深度可能會有所不同。

我知道os.walk,但是我的目錄中有200萬個文件,因此os.walk的速度很慢。

目前,下面的代碼對我有用,但是我懷疑可能會有更簡單的方法/循環來實現相同的結果,並且我想知道如何對其進行改進。 同樣,我功能的局限性在於它仍然受到我可以遍歷子目錄的深度的限制,也許可以克服。

def list_directories(path):
dir_list = []
for entry in scandir(path):
    if entry.is_dir():
        dir_list.append(entry.path)
        for entry2 in scandir(entry.path):
            if entry2.is_dir():
                dir_list.append(entry2.path)
                for entry3 in scandir(entry2.path):
                    if entry3.is_dir():
                        dir_list.append(entry3.path)
                        for entry4 in scandir(entry3.path):
                            if entry4.is_dir():
                                dir_list.append(entry4.path)
                                for entry5 in scandir(entry4.path):
                                    if entry5.is_dir():
                                        dir_list.append(entry5.path)
                                        for entry6 in scandir(entry5.path):
                                            if entry6.is_dir():
                                                dir_list.append(entry6.path)
return dir_list
for item in filelist_dir(directory):
    print item

請讓我知道,如果您有更好的替代方法,可以快速返回包含數百萬個文件的路徑中的所有目錄和子目錄。

scandir支持walk()函數,該函數包含對scandir()的相同優化,因此它應該比os.walk()更快。 (scandir的背景部分建議在Linux / Mac OS X上將時間縮短3-10倍。)

因此,您可以使用它……像這樣的代碼可能會起作用:

from scandir import walk

def list_directories(path):
    dir_list = []
    for root, _, _ in walk(path):
        # Skip the top-level directory, same as in your original code:
        if root == path:
            continue
        dir_list.append(root)
    return dir_list

如果要改為使用scandir()來實現此目的,則要實現支持任意深度的功能,應使用遞歸。

就像是:

from scandir import scandir

def list_directories(path):
    dir_list = []
    for entry in scandir(path):
        if entry.is_dir() and not entry.is_symlink():
            dir_list.append(entry.path)
            dir_list.extend(list_directories(entry.path))
    return dir_list

注意 :我也添加了對is_symlink()的檢查,因此它不會遍歷符號鏈接。 否則指向“。”的符號鏈接。 或“ ..”將使此遞歸永遠...

我仍然認為使用scandir.walk()更好(更簡單,更可靠),因此如果適合您,請改用它!

首先,為了避免限制6個目錄,您可能需要遞歸執行此操作:

def list_directories(path):
    dir_list = []
    for entry in scandir(path):
        if entry.is_dir():
            dir_list.append(entry.path)
            dir_list.extend(list_directories(entry.path))

另外,由於您使用的是Python 2.7,所以os.walk太慢的部分原因是Python 2.7使用listdir而不是scandir進行walk scandir backport軟件包包括自己的walk實現(與Python 3.5中使用的基本相同),它提供與walk相同的API,但具有極大的提速(特別是在Windows上)。


除此之外,您的主要性能成本可能取決於平台。

在Windows上,主要是讀取目錄條目的成本。 實際上,您對此無能為力。 scandir已經以最快的方式執行此操作。

在POSIX上,可能主要是stat每個文件是否為目錄的成本。 您可以使用fts加快速度(尤其是在Linux上),但是據我所知,沒有適合它的Python包裝器。 如果您知道ctypes ,則調用它並不那么復雜; 困難的部分是想出一個好的設計,以便將其所有功能公開給Python(當然,您不需要這樣做)。 如果您想自己嘗試,請在GitHub上查看我未完成的庫


或者,您可能需要使用find (使用fts被窩里),或者通過駕駛它subprocess ,或有它推動你的腳本。


最后,您可能希望並行執行操作。 如果您的文件系統是舊筆記本電腦硬盤,而不是例如兩個SSD和帶有高端控制器的RAID條帶,那么這實際上可能會減慢速度,而不是加快速度。 因此,絕對可以嘗試一下,然后再投入太多。

如果您要做的事情不那么繁瑣,那么可能只需要一個步行線程就可以為工作人員排隊以便進行工作的目錄。

如果步行是重點,那么您將希望並行拉動多個步行者。 concurrent.futures.ThreadPoolExecutor打包內容的方式可能剛好夠好,而且非常簡單。 為了獲得最大速度,您可能需要手動排隊並分批拉動它們,按物理量對工作進行分片等,但是可能不需要這樣做。 (如果是這樣,並且如果您可以混淆閱讀Rust代碼, ripgrep進行大量工作以盡可能快地瀏覽文件系統。)

您可以使用python內置模塊os.walk

for root, dirs, files in os.walk(".", topdown=False):
   for name in files:
      print(os.path.join(root, name))
   for name in dirs:
      #this will get your all directories within the path
      print(os.path.join(root, name))

有關更多信息,請訪問此鏈接: os.walk

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM