2009年10月25日 星期日

目錄掃描工具


以深度優先方式作 recursive file scan
#define _CRT_SECURE_NO_WARNINGS
#include <ctype.h>
#include <io.h>
#include <stdio.h>
#include <math.h>
#include <conio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;


//串接路徑 dir 與後續名稱 name, 存入 out

void path_cat (char* out, char* dir, char* name)
{
    int   i  = strlen (dir);
    char  ch = dir[i-1];

    strcpy (out, dir);
    if (ch!='/' && ch!='\\') {       //尾端需要補'/'嗎?
        out[i]   = '/';
        out[++i] = '\0';
    }
    strcpy (out+i, name);                  
}

template <class TClass>
struct ScanDir
{
    typedef void (TClass::*PFT)();      //Type of member function pointer
    TClass*      obj;                   //pointer to processing object
    PFT          process_enter;
    PFT          process_each_scan;

    enum {MAX_LEVEL = 16};              //進行掃描時的最大遞迴層數
    char**       path;                  //每層的暫存路徑
    int          curLevel;              //目前掃描到的層數
    int          nSubDir;               //目前掃描到的層, 當中的子目錄個數
    _finddata_t* curFile;               //目前掃描到的檔案資訊
    char*        curDir;                //目前掃描到的目錄名稱
    int          nFilter;               //欲處理的副檔名數目, 最多 32 筆
    char         filter[32][8];         //欲處理的副檔名集合, 最多 32 筆

    ScanDir()
    {
        path = (char**) new_arr (sizeof(char), 2, MAX_LEVEL, 256);
    }
   ~ScanDir()
    {
        del_arr (path);
    }

    // 裝載搜索資訊
    // sFilter = 欲處理的副檔名集合, 以.分隔與結束, 如: "html.flash."
   
    void setup (TClass* ref, PFT enter, PFT scan, char* sFilter=0)  
    {
        obj               = ref;
        process_enter     = enter;
        process_each_scan = scan;
        nFilter           = 0;
        if (sFilter)
            for (char* p=sFilter; *p; ++p)
                if (*p == '.') {
                    strncpy (filter[nFilter], sFilter, p-sFilter);
                    filter [nFilter][p-sFilter] = '\0';
                    nFilter++;
                    sFilter = p+1;
                } 
    }
    bool match_filter ()                            //過濾副檔名
    {                                               //若副檔名存在 filter
        int   i;                                    //集合中則回傳 true
        char* s = curFile->name;
        char* p = s + strlen (s) - 1;

        for (i=0 ;p>s && i<8; ++i, --p)
            if (*p == '.') {p++; break;}
        if (i > 0)                                  //副檔名至少要有一個字元
            for (i=0; i<nFilter; ++i)
                if (strcmp (p, filter[i]) == 0)
                    return true;           
        return false;
    }
   
    void scan (char* dir, int level=0)              //dir 必須是目錄名稱
    {
        char* s = path[level];
        path_cat (s, dir, "*.*");

        _finddata_t file;
        long hFile = _findfirst (s, &file);
        if (hFile == -1) {
            puts ("No files in current directory");
            return;
        }   
        curDir   = dir;
        curLevel = level;                           //紀錄目前掃描到的層數
        nSubDir  = 0;                               //計算當前目錄中
        do if ((file.attrib & _A_SUBDIR) &&         //子目錄的個數
                strcmp (file.name, ".") != 0 &&
                strcmp (file.name,"..") != 0)       //若 nSubDir = 0
            nSubDir++;                              //表示已掃描到葉節點
        while (_findnext (hFile, &file) == 0);
        _findclose (hFile);

        (obj->*process_enter)();                    //執行進入目錄時的
                                                    //前置處理
        hFile = _findfirst (s, &file);
        do {
            if (file.attrib & _A_SUBDIR) {          //若是目錄
                if (strcmp (file.name, ".") != 0 &&
                    strcmp (file.name,"..") != 0) {
                    path_cat (s, dir, file.name);                  
                    scan (s, level+1);
                }
            } else {
                curFile = &file;
                if (nFilter && match_filter())      //對符合過濾條件的
                    (obj->*process_each_scan)();    //檔案進行特定處理
            }
        }
        while (_findnext (hFile, &file) == 0);
        _findclose (hFile);
    }
};

測試程式:
struct Test
{
    int n;
    ScanDir<Test> scan_dir;
    void in_each_scan ()
    {
        _finddata_t* f = scan_dir.curFile;
        char* type = (f->attrib & _A_SUBDIR)? "目錄":"檔案";
        printf("\nLevel: %2d, [%3d] %s %s",
            scan_dir.curLevel, n++, type, f->name);
        getch();
    }
    void at_enter ()
    {
        printf ("\n------------ %s -------------", scan_dir.curDir);
    }

    void scan (char* path)
    {
        if (_access (path,0) != 0) {
            printf ("%s 目錄不存在!", path);
            getch(); return;
        }
        n = 0;
        scan_dir.setup (this, &Test::at_enter, &Test::in_each_scan,
            "jpg.bmp.png.gif.jpeg."); 
        scan_dir.scan (path);
    }
};

int main()
{
    char path[512] = "../../image/DM/" ;
    Test test;
    test.scan (path);
    return getch();
}

沒有留言:

張貼留言