簡體   English   中英

在Python中遍歷目錄樹的合理更快的方法是什么?

[英]Reasonably faster way to traverse a directory tree in Python?

假設給定的目錄樹大小合理:比如像Twisted或Python這樣的開源項目,那么遍歷和遍歷該目錄中所有文件/目錄的絕對路徑的最快方法是什么?

我想在Python中做到這一點。 os.path.walk很慢。 所以我嘗試了ls -lRtree -fi 對於包含大約8337個文件的項目(包括tmp,pyc,test,.svn文件):

$ time tree -fi > /dev/null 

real    0m0.170s
user    0m0.044s
sys     0m0.123s

$ time ls -lR > /dev/null 

real    0m0.292s
user    0m0.138s
sys     0m0.152s

$ time find . > /dev/null 

real    0m0.074s
user    0m0.017s
sys     0m0.056s
$

tree似乎比ls -lR快(雖然ls -Rtree快,但它不提供完整路徑)。 find是最快的。

任何人都可以想到更快和/或更好的方法嗎? 在Windows上,如果需要,我可能只是發送一個32位二進制tree.exe或ls.exe。

更新1 :添加了find

更新2 :為什么我要這樣做? ...我正在嘗試巧妙地替換cd,pushd等...以及依賴於傳遞路徑的其他命令的包裝命令(更少,更多,cat,vim,tail)。 程序將偶爾使用文件遍歷來執行此操作(例如:鍵入“cd sr grai pat lxml”將自動轉換為“cd src / pypm / grail / patches / lxml”)。 如果這個替換CD需要半秒才能運行,我將不會感到滿意。 請參閱http://github.com/srid/pf

即使os.path.walk沒有花時間,你在pf中的方法也會無可救葯地緩慢。 在所有現存路徑上進行包含3個無界閉包的正則表達式匹配將會在那里殺死你。 以下是我引用的Kernighan和Pike的代碼,這是一個適合該任務的算法:

/* spname:  return correctly spelled filename */
/*
 * spname(oldname, newname)  char *oldname, *newname;
 *  returns -1 if no reasonable match to oldname,
 *           0 if exact match,
 *           1 if corrected.
 *  stores corrected name in newname.
 */

#include <sys/types.h>
#include <sys/dir.h>

spname(oldname, newname)
    char *oldname, *newname;
{
    char *p, guess[DIRSIZ+1], best[DIRSIZ+1];
    char *new = newname, *old = oldname;

    for (;;) {
        while (*old == '/') /* skip slashes */
            *new++ = *old++;
        *new = '\0';
        if (*old == '\0')   /* exact or corrected */
            return strcmp(oldname,newname) != 0;
        p = guess;  /* copy next component into guess */
        for ( ; *old != '/' && *old != '\0'; old++)
            if (p < guess+DIRSIZ)
                *p++ = *old;
        *p = '\0';
        if (mindist(newname, guess, best) >= 3)
            return -1;  /* hopeless */
        for (p = best; *new = *p++; ) /* add to end */
            new++;                    /* of newname */
    }
}

mindist(dir, guess, best)   /* search dir for guess */
    char *dir, *guess, *best;
{
    /* set best, return distance 0..3 */
    int d, nd, fd;
    struct {
        ino_t ino;
        char  name[DIRSIZ+1];   /* 1 more than in dir.h */
    } nbuf;

    nbuf.name[DIRSIZ] = '\0';   /* +1 for terminal '\0' */
    if (dir[0] == '\0')     /* current directory */
        dir = ".";
    d = 3;  /* minimum distance */
    if ((fd=open(dir, 0)) == -1)
        return d;
    while (read(fd,(char *) &nbuf,sizeof(struct direct)) > 0)
        if (nbuf.ino) {
            nd = spdist(nbuf.name, guess);
            if (nd <= d && nd != 3) {
                strcpy(best, nbuf.name);
                d = nd;
                if (d == 0)     /* exact match */
                    break;
            }
        }
    close(fd);
    return d;
}

/* spdist:  return distance between two names */
/*
 *  very rough spelling metric:
 *  0 if the strings are identical
 *  1 if two chars are transposed
 *  2 if one char wrong, added or deleted
 *  3 otherwise
 */

#define EQ(s,t) (strcmp(s,t) == 0)

spdist(s, t)
    char *s, *t;
{
    while (*s++ == *t)
        if (*t++ == '\0')
            return 0;       /* exact match */
    if (*--s) {
        if (*t) {
            if (s[1] && t[1] && *s == t[1] 
              && *t == s[1] && EQ(s+2, t+2))
                return 1;   /* transposition */
            if (EQ(s+1, t+1))
                return 2;   /* 1 char mismatch */
        }
        if (EQ(s+1, t))
            return 2;       /* extra character */
    }
    if (*t && EQ(s, t+1))
        return 2;           /* missing character */
    return 3;
}

注意 :此代碼是在ANSI C,ISO C或POSIX之前編寫的,當一個讀取目錄文件為raw時,甚至可以想象。 代碼的方法遠比所有指針吊索更有用。

在性能方面find它會好得多,但問題是速度有多快,為什么你需要這么快? 你聲稱os.path.walk很慢,實際上,它在我的機器上比16k目錄的樹慢約3倍。 但話說回來,我們正在討論Python的0.68秒和1.9秒之間的差異。

如果設定一個速度記錄是你的目標,你不能擊敗硬編碼C,這完全是75%的系統調用限制,你不能讓操作系統更快。 也就是說,25%的Python時間花在了系統調用上。 你想用遍歷的路徑做什么?

你沒有提到的一個解決方案是'os.walk'。 我不確定它會比os.path.walk更快,但它客觀上更好。

當你擁有目錄列表時,你還沒有說明你要做什么,所以很難給出更具體的建議。

雖然我懷疑你有多個讀頭,但這里是你如何遍歷幾百萬個文件(我們在幾分鍾內完成了10M +)。

https://github.com/hpc/purger/blob/master/src/treewalk/treewalk.c

暫無
暫無

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

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