Linux C/C++ 利用scandir和alphasort遍歷目錄文件並排序


之前講述了如何利用readdir/readdir_r,對指定目錄進行遍歷並輸出,參見:Linux C 講解系統調用readdir, readdir_r 以及如何遍歷目錄下的所有文件

這里講述利用scandir和alphasort如何遍歷指定目錄,並對文件名排序輸出。

scandir,alphasort,versionsort

scandir,alphasort,versionsort 可搭配用於掃描指定目錄dirp(不含子目錄)下,滿足filter過濾模式的文件,返回的結果通過qsort排序存放到namelist數組中(由scandir函數調用malloc分配空間),比較子用的是compar。

函數原型

查看man scandir(3)

#include <dirent.h>

int scandir(const char *dirp, struct dirent ***namelist,
      int (*filter)(const struct dirent *),
      int (*compar)(const struct dirent **, const struct dirent **));

int alphasort(const void *a, const void *b);
int versionsort(const void *a, const void *b);

alphasort和versionsort

alphasort和versionsort 作為比較函數,原型相同,可傳遞給compar。其區別是,
1)遵循的標准不一樣
scandir,alphasort和遵循POSIX.1-2008;
versionsort是GNU擴展;
也就是說,兩者需要的宏定義不一樣:alphasort需要_BSD_SOURCE || _SVID_SOURCE支持,versionsort需要_GNU_SOURCE支持。

2)實現時,調用的比較函數不一樣
alphasort調用的是strcoll,versionsort調用的是strverscmp。

  • 對於strcoll:
    比較是基於字符串被解釋為,適合當前語言環境的LC_COLLATE類別,也就是說大多數情況下,字符串是ASCII編碼。

  • 對於strverscmp:
    strcmp會將文件jan1, jan2, ..., jan9, jan10,排成字典序jan1, jan10, ..., jan2, ..., jan9。而strverscmp將里面的數字做了修正,會得到jan1, jan2, ..., jan9, jan10這樣的排序。
    其比較的字符串並非LC_COLLATE

  • LC_COLLATE的描述參見man setlocale(3)

LC_COLLATE
              for regular expression matching (it determines the  meaning  of  range
              expressions and equivalence classes) and string collation.

翻譯一下:

對於正則表達式匹配 (它決定了范圍表達式和等價類的含義)和字符串校勘。

從這里看不出什么,可參見這篇文章setlocale()函數詳解——C語言,可知,用setlocale設置LC_COLLATE會影響strcoll和strxfrm,其C字符串是ASCII編碼。

示例

用scandir和alphasort,scandir和versionsort 分別順序、逆序打印指定目錄下的文件名。
注意:打印文件的順序,跟使用的比較函數無關,而是取決於變量存放結果的namelist的訪問順序。

#include <dirent.h>
#include <stdio.h>

/* 順序打印指定目錄下文件 */
void test_scandir1()
{
    struct dirent **namelist;
    int n;
    n = scandir(".", &namelist, NULL, alphasort);
    if (n < 0)
        perror("scandir error");
    else
    {
        for (int m = 0; m < n; ++m)
        {
            printf("%s\n", namelist[m]->d_name);
            free(namelist[m]);
        }
        free(namelist);
    }
}

/* 逆序打印指定目錄下文件 */
void test_scandir2()
{
    struct dirent **namelist;
    int n;
    n = scandir(".", &namelist, NULL, versionsort);
    if (n < 0)
        perror("scandir error");
    else
    {
        while (n--)
        {
            printf("%s\n", namelist[n]->d_name);
            free(namelist[n]);
        }
        free(namelist);
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM