最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python中線上目錄遍歷的避坑指南

 更新時(shí)間:2026年06月05日 08:28:40   作者:幸福清風(fēng)  
做服務(wù)器運(yùn)維、日志歸檔、磁盤巡檢、過期文件清理時(shí),幾乎人人都要寫目錄遍歷腳本,線上目錄遠(yuǎn)比本地測(cè)試環(huán)境復(fù)雜,本文小編為大家整理了一些Python中線上目錄遍歷的避坑方法,希望對(duì)大家有所幫助

前言

做服務(wù)器運(yùn)維、日志歸檔、磁盤巡檢、過期文件清理時(shí),幾乎人人都要寫目錄遍歷腳本。很多新手隨手os.listdir一層遍歷,本地測(cè)試幾個(gè)文件跑得飛快,一丟線上環(huán)境直接翻車:權(quán)限報(bào)錯(cuò)中斷程序、軟鏈接無限遞歸死循環(huán)、海量小文件撐爆內(nèi)存、文件中途被刪除觸發(fā)異常崩潰。

線上目錄遠(yuǎn)比本地測(cè)試環(huán)境復(fù)雜:數(shù)十萬(wàn)細(xì)碎業(yè)務(wù)文件、帶空格/中文/特殊符號(hào)的文件名、無權(quán)限的緩存目錄、指向父級(jí)的軟鏈接、業(yè)務(wù)進(jìn)程實(shí)時(shí)增刪文件,一套能扛住生產(chǎn)環(huán)境的遍歷代碼,核心從來不是實(shí)現(xiàn)遞歸,而是兜底各類異常、規(guī)避環(huán)境陷阱。

一、新手通用踩坑寫法:?jiǎn)螌觢istdir,線上完全不堪用

最經(jīng)典的入門遍歷寫法,僅能讀取同級(jí)目錄,既無法遞歸深層目錄,也沒有任何異常捕獲,碰到權(quán)限目錄腳本直接PermissionError終止,也就是開篇日志卡在.cache權(quán)限目錄的根源。

import os
root = "/data/upload"
for name in os.listdir(root):
    path = os.path.join(root, name)
    print(path)

適用場(chǎng)景僅限本地臨時(shí)查看目錄,嚴(yán)禁用于生產(chǎn)文件統(tǒng)計(jì)、過期清理、磁盤巡檢。一旦遇到子目錄、權(quán)限隔離目錄、瞬時(shí)刪除的目錄,程序直接異常退出,前面掃描成果全部作廢。

二、生產(chǎn)優(yōu)選:os.scandir替代listdir,精準(zhǔn)區(qū)分文件與目錄

os.scandir相比os.listdir優(yōu)勢(shì)巨大:返回DirEntry對(duì)象,自帶文件類型屬性,無需額外os.path.isdir/isfile重復(fù)系統(tǒng)IO,遍歷效率更高;搭配follow_symlinks=False屏蔽軟鏈接跟隨,從根源杜絕軟鏈接指向父目錄造成的無限遞歸。

單層安全遍歷模板,提前校驗(yàn)路徑是否存在、是否為目錄,非法路徑直接日志跳過:

from pathlib import Path
import os

def scan_one_level(folder: str):
    base = Path(folder)
    if not base.exists():
        print(f"[bad_path] not exists: {base}")
        return
    if not base.is_dir():
        print(f"[bad_path] not dir: {base}")
        return
    # 上下文管理器自動(dòng)釋放資源
    with os.scandir(base) as items:
        for item in items:
            # 禁止跟隨軟鏈接,防止死循環(huán)
            if item.is_dir(follow_symlinks=False):
                print(f"[dir ] {item.path}")
            elif item.is_file(follow_symlinks=False):
                print(f"[file] {item.path}")
            else:
                print(f"[skip] {item.path}")

scan_one_level("/data/upload")

線上坑點(diǎn)總結(jié):不加follow_symlinks=False,碰到環(huán)形軟鏈接,腳本會(huì)無限遞歸,拉高磁盤IO占用,拖垮服務(wù)器。

三、自定義棧式遞歸遍歷:可控性完勝原生os.walk

原生os.walk可以實(shí)現(xiàn)遞歸遍歷,但自定義棧結(jié)構(gòu)能靈活控制遍歷深度、攔截異常、按需跳過目錄,是生產(chǎn)環(huán)境首選方案。
核心設(shè)計(jì)思路:用棧保存(目錄路徑, 當(dāng)前層級(jí)),循環(huán)出棧遍歷,通過max_depth限制遞歸深度,逐層捕獲權(quán)限不足、目錄已刪除、讀取失敗等所有異常,只打印錯(cuò)誤日志,不終止主程序。

完整可復(fù)用生成器代碼:

from pathlib import Path
import os

def walk_files(root: str, max_depth: int = 20):
    start = Path(root).resolve()
    stack = [(start, 0)]
    while stack:
        folder, depth = stack.pop()
        # 超出設(shè)定深度直接跳過
        if depth > max_depth:
            print(f"[skip_depth] {folder}")
            continue
        try:
            with os.scandir(folder) as entries:
                for entry in entries:
                    path = Path(entry.path)
                    try:
                        # 目錄入棧實(shí)現(xiàn)遞歸,不跟隨軟鏈接
                        if entry.is_dir(follow_symlinks=False):
                            stack.append((path, depth + 1))
                            continue
                        # 文件通過yield逐個(gè)返回,惰性加載不占內(nèi)存
                        if entry.is_file(follow_symlinks=False):
                            yield path
                    except OSError as e:
                        print(f"[entry_error] path={path} err={e}")
        except PermissionError as e:
            # 無權(quán)限目錄記錄日志,繼續(xù)遍歷其他目錄
            print(f"[no_permission] path={folder} err={e}")
        except FileNotFoundError:
            # 遍歷瞬間目錄被業(yè)務(wù)刪除,常見于動(dòng)態(tài)上傳目錄
            print(f"[gone] path={folder}")
        except OSError as e:
            print(f"[scan_error] path={folder} err={e}")

關(guān)鍵設(shè)計(jì)亮點(diǎn)

  1. yield惰性迭代:逐個(gè)產(chǎn)出文件路徑,不用一次性把全量文件存入列表,海量小文件場(chǎng)景避免內(nèi)存溢出,腳本意外中斷,已掃描數(shù)據(jù)已有輸出;
  2. 全鏈路異常捕獲:區(qū)分權(quán)限不足、目錄消失、讀取異常三類生產(chǎn)高頻報(bào)錯(cuò),異常僅日志記錄,不中斷全量掃描;
  3. 深度限制max_depth防止意外遍歷系統(tǒng)根目錄無限下沉,規(guī)避掃描全磁盤帶來的IO風(fēng)暴。

調(diào)用示例:

for file_path in walk_files("/data/upload"):
    print(file_path)

四、基于通用遍歷器,封裝四大生產(chǎn)高頻業(yè)務(wù)腳本

依托walk_files生成器,可快速封裝超大文件排查、后綴篩選、磁盤占用統(tǒng)計(jì)、過期文件清理四類運(yùn)維常用工具,所有腳本延續(xù)異常捕獲、安全校驗(yàn)邏輯。

掃描超大文件:排查磁盤異常暴漲

自動(dòng)篩選超過指定MB的文件,捕獲文件無法獲取大小的異常:

def find_big_files(root: str, limit_mb: int = 100):
    limit = limit_mb * 1024 * 1024
    for path in walk_files(root):
        try:
            size = path.stat().st_size
        except OSError as e:
            print(f"[stat_error] path={path} err={e}")
            continue
        if size >= limit:
            print(f"[big_file] size_mb={size / 1024 / 1024:.1f} path={path}")

find_big_files("/data/upload", 100)

按后綴過濾文件:日志、臨時(shí)文件定向篩選

統(tǒng)一小寫后綴匹配,規(guī)避大小寫后綴漏匹配問題:

def iter_by_suffix(root: str, suffixes: set[str]):
    suffixes = {s.lower() for s in suffixes}
    for path in walk_files(root):
        if path.suffix.lower() in suffixes:
            yield path

# 只遍歷.log .txt文件
for log_file in iter_by_suffix("/data/app", {".log", ".txt"}):
    print(f"[match] {log_file}")

目錄磁盤占用匯總:快速定位耗空間文件類型

按文件后綴匯總數(shù)量與占用空間,從大到小排序,排查磁盤爆滿神器:

from collections import defaultdict

def summary_folder(root: str):
    counter = defaultdict(int)
    size_map = defaultdict(int)
    for path in walk_files(root):
        suffix = path.suffix.lower() or "<no_ext>"
        try:
            size = path.stat().st_size
        except OSError as e:
            print(f"[stat_error] path={path} err={e}")
            continue
        counter[suffix] += 1
        size_map[suffix] += size
    # 按占用空間倒序輸出
    rows = sorted(size_map.items(), key=lambda x: x[1], reverse=True)
    for suffix, total_size in rows:
        print(f"{suffix:10s} count={counter[suffix]:6d} size_mb={total_size / 1024 / 1024:10.2f}")

summary_folder("/data/upload")

過期臨時(shí)文件清理:dry_run試運(yùn)行杜絕誤刪

生產(chǎn)清理鐵律:先試運(yùn)行、后真實(shí)刪除,通過dry_run開關(guān)控制,試運(yùn)行僅打印待刪文件,確認(rèn)無誤再關(guān)閉試運(yùn)行執(zhí)行刪除,避免路徑傳參錯(cuò)誤、邏輯bug導(dǎo)致批量誤刪業(yè)務(wù)文件。

import time
def delete_old_tmp(root: str, days: int = 30, dry_run: bool = True):
    now = time.time()
    expire_seconds = days * 24 * 3600
    for path in iter_by_suffix(root, {".tmp", ".bak"}):
        try:
            mtime = path.stat().st_mtime
        except OSError as e:
            print(f"[stat_error] path={path} err={e}")
            continue
        if now - mtime <= expire_seconds:
            continue
        if dry_run:
            print(f"[dry_run] delete {path}")
            continue
        try:
            path.unlink()
            print(f"[deleted] {path}")
        except OSError as e:
            print(f"[delete_error] path={path} err={e}")
# 先試運(yùn)行,確認(rèn)輸出無誤再改為False
delete_old_tmp("/data/upload/tmp", 30, dry_run=True)

五、線上運(yùn)行避坑五條鐵律

  1. 軟鏈接必禁跟隨:所有is_dir/is_file強(qiáng)制follow_symlinks=False,杜絕環(huán)形軟鏈接死遞歸;
  2. 異常絕不裸奔:權(quán)限不足、文件瞬時(shí)刪除、stat獲取大小失敗全部捕獲打日志,單個(gè)目錄異常不能中斷全局掃描;
  3. 拒絕全量加載內(nèi)存:統(tǒng)一用yield惰性迭代文件,不用list一次性裝載全量路徑,適配百萬(wàn)級(jí)小文件目錄;
  4. 文件刪除先演練:清理腳本默認(rèn)dry_run試運(yùn)行,肉眼核對(duì)待刪列表后再開啟真實(shí)刪除;
  5. 限制掃描范圍與深度:不直接從/根目錄全量掃描,限定業(yè)務(wù)目錄+最大遞歸深度,防止全盤掃描打爆磁盤IO。

結(jié)語(yǔ)

目錄遍歷代碼語(yǔ)法簡(jiǎn)單,但適配生產(chǎn)環(huán)境的核心在于兼容各種異常場(chǎng)景。本地測(cè)試能用的簡(jiǎn)易代碼,放到復(fù)雜的線上服務(wù)器大概率出錯(cuò)。少追求代碼精簡(jiǎn)優(yōu)雅,多做路徑校驗(yàn)、異常捕獲、運(yùn)行兜底,運(yùn)維腳本才能在深夜自動(dòng)巡檢時(shí)安穩(wěn)運(yùn)行,減少突發(fā)故障與誤刪事故。

到此這篇關(guān)于Python中線上目錄遍歷的避坑指南的文章就介紹到這了,更多相關(guān)Python目錄遍歷內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

大竹县| 河南省| 赤峰市| 广平县| 长垣县| 资兴市| 城口县| 禹州市| 吴堡县| 洛扎县| 惠东县| 齐河县| 湘乡市| 济南市| 西乌珠穆沁旗| 南宁市| 鹤壁市| 保康县| 建阳市| 澳门| 阳曲县| 吉安县| 上思县| 承德县| 中山市| 佛坪县| 高密市| 兴仁县| 达拉特旗| 庆安县| 诏安县| 涟源市| 镇康县| 江孜县| 南丹县| 宾川县| 寻乌县| 西宁市| 攀枝花市| 温宿县| 错那县|