閱讀266 返回首頁    go 京東網上商城


Linux下文件分發的算法設計及C代碼實現

**需求描述 **
在Linux係統的某個源目錄中有一批後綴相同的文件,編寫程序將這些文件按照前綴分發到不同的目錄中。

例如,源目錄SourceDir中存放有三個後綴相同的文件File1_1.txt、File2_1.txt和File3_1.txt,按照前綴File1_、File2_和File3_將它們分別移動(分發)到目錄FileDir1、FileDir2和FileDir3中。

算法設計
基於需求,可以采用如圖1所示的程序流程:
1

圖1 程序總體流程

**特殊流程考慮 **
在編寫程序的過程中,對於某些特殊流程的考慮如下:
1.如果掃描源目錄出錯,則直接停止程序的運行,而不用繼續掃描下一個目錄。

2.對於某些空文件(即文件的大小為0),直接在源目錄中將其刪除,而不用進行分發。

3.為了隨時能夠處理放到源目錄中的文件,程序每隔一段時間(如一分鍾)掃描一次源目錄。也就是說,如果不人為操作,程序啟動之後會不停地運行。

程序代碼

/**********************************************************************
* 版權所有 (C)2016, Zhou Zhaoxiong。
*
* 文件名稱:FileDistribute.c
* 文件標識:無
* 內容摘要:將某個目錄中的文件按照前綴分發到對應的目錄中
* 其它說明:無
* 當前版本:V1.0
* 作    者:Zhou Zhaoxiong
* 完成日期:20160517
*
**********************************************************************/
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <ftw.h>
#include <time.h>

// 重定義數據類型
typedef signed   int        INT32;
typedef unsigned int        UINT32;
typedef unsigned char       UINT8;

// 全局變量定義
UINT8  g_szSourceDir[256] = {0};     // 源文件的目錄

// 函數聲明
INT32 SelectFlies(struct dirent *pDir);
void ScanDirAndDistribute(void);
void Sleep(UINT32 iCountMs);


/****************************************************************
* 功能描述: 主函數
* 輸入參數: 無
* 輸出參數: 無
* 返 回 值: 0-執行完成
* 其他說明: 無
* 修改日期       版本號        修改人        修改內容
* -------------------------------------------------------------
* 20160517        V1.0     Zhou Zhaoxiong     創建
****************************************************************/
INT32 main(void)
{
    // 源文件的目錄
    snprintf(g_szSourceDir, sizeof(g_szSourceDir)-1, "%s/zhouzx/TestDir/SourceDir", getenv("HOME"));

    // 調用函數執行文件的分發
    while (1)
    {
        ScanDirAndDistribute();

        Sleep(60 * 1000);    // 每一分鍾執行一次文件的分發
    }

    return 0;
}


/**********************************************************************
* 功能描述:根據後綴選擇文件
* 輸入參數:dir-目錄
* 輸出參數:無
* 返 回 值:0-失敗   1-成功
* 其它說明:一個形如test.txt的文件要被掃描出來, 而形如test的文件不符合條件
* 修改日期         版本號      修改人          修改內容
* --------------------------------------------------------------------
* 20160517         V1.0    ZhouZhaoxiong        創建
***********************************************************************/
INT32 SelectFlies(struct dirent *pDir)
{
    if (pDir == NULL)
    {
        printf("SelectFlies:input parameter is NULL!\n");
        return 0;
    }

    // 根據.txt(後綴)選擇文件
    if (strstr(pDir->d_name, ".txt") != NULL)
    {
        return 1;         // 找到了滿足條件的文件
    }
    else
    {
        return 0;
    }
}


/**********************************************************************
* 功能描述:掃描目錄並分發文件
* 輸入參數:無
* 輸出參數:無
* 返 回 值:無
* 其它說明:無
* 修改日期         版本號      修改人          修改內容
* --------------------------------------------------------------------
* 20160517         V1.0    ZhouZhaoxiong        創建
***********************************************************************/
void ScanDirAndDistribute(void)
{
    INT32  iScanDirRet           = 0;
    UINT32 iFileIdx              = 0;
    UINT32 iFileCount            = 0;
    UINT32 iFileSize             = 0;
    UINT8  szFileDir[256]        = {0};
    UINT8  szScanedFile[512]     = {0};
    UINT8  szCmdBuf[256]         = {0};
    FILE  *fp                    = NULL;
    struct dirent **ppDirEnt     = NULL;

    // 掃描源目錄, 並分發文件
    iScanDirRet = scandir(g_szSourceDir, &ppDirEnt, SelectFlies, alphasort);
    if (iScanDirRet < 0)   // 掃描目錄出錯
    {
        printf("ScanDirAndDistribute:exec scandir failed, path=%s\n", g_szSourceDir);
        return;
    }
    else if (iScanDirRet == 0)   // 目錄下無文件
    {
        printf("ScanDirAndDistribute:no satisfied file in directory %s\n", g_szSourceDir);
    }
    else          // 將滿足條件的文件移動到對應的目錄中
    {
        for (iFileIdx = 0; iFileIdx < iScanDirRet; iFileIdx ++)
        {
            // 先判斷掃描到的文件是否為空文件, 是則直接刪除, 不是才執行移動的操作
            memset(szScanedFile, 0x00, sizeof(szScanedFile));
            snprintf(szScanedFile, sizeof(szScanedFile) - 1, "%s/%s", g_szSourceDir, ppDirEnt[iFileIdx]->d_name);
            fp = fopen(szScanedFile, "r");
            if (fp == NULL)          // 打開文件失敗, 直接返回
            {
                printf("ScanDirAndDistribute:open file %s failed, please check!\n", szScanedFile);
                return;
            }
            fseek(fp, 0, SEEK_END);
            iFileSize = ftell(fp);
            if (iFileSize == 0)     // 該文件為空文件
            {
                printf("ScanDirAndDistribute:%s is an empty file, so delete it directly!\n", szScanedFile);
                memset(szCmdBuf, 0x00, sizeof(szCmdBuf));
                snprintf(szCmdBuf, sizeof(szCmdBuf) - 1, "rm %s", szScanedFile);
                system(szCmdBuf);
            }
            else   // 根據前綴將文件移動(分發)到對應的目錄中
            {
                if (strncmp(ppDirEnt[iFileIdx]->d_name, "File1_", strlen("File1_")) == 0)    // 移動到FileDir1
                {
                    memset(szFileDir, 0x00, sizeof(szFileDir));
                    snprintf(szFileDir, sizeof(szFileDir)-1, "%s/zhouzx/TestDir/FileDir1", getenv("HOME"));
                }
                else if (strncmp(ppDirEnt[iFileIdx]->d_name, "File2_", strlen("File2_")) == 0)    // 移動到FileDir2
                {
                    memset(szFileDir, 0x00, sizeof(szFileDir));
                    snprintf(szFileDir, sizeof(szFileDir)-1, "%s/zhouzx/TestDir/FileDir2", getenv("HOME"));
                }
                else if (strncmp(ppDirEnt[iFileIdx]->d_name, "File3_", strlen("File3_")) == 0)    // 移動到FileDir3
                {
                    memset(szFileDir, 0x00, sizeof(szFileDir));
                    snprintf(szFileDir, sizeof(szFileDir)-1, "%s/zhouzx/TestDir/FileDir3", getenv("HOME"));
                }
                else    // 前綴不滿足, 直接將該文件刪掉
                {
                    memset(szCmdBuf, 0x00, sizeof(szCmdBuf));
                    snprintf(szCmdBuf, sizeof(szCmdBuf) - 1, "rm %s", szScanedFile);
                    system(szCmdBuf);

                    printf("ScanDirAndDistribute:now, %s\n", szCmdBuf);

                    continue;  // 繼續判斷下一個
                }

                memset(szCmdBuf, 0x00, sizeof(szCmdBuf));
                snprintf(szCmdBuf, sizeof(szCmdBuf) - 1, "mv %s %s", szScanedFile, szFileDir);
                system(szCmdBuf);

                printf("ScanDirAndDistribute:now, %s\n", szCmdBuf);

                iFileCount ++;
            }
        }
    }

    printf("ScanDirAndDistribute:this time,totally moved %d file(s).\n", iFileCount);

    return;
}


/**********************************************************************
* 功能描述: 程序休眠
* 輸入參數: iCountMs-休眠時間(單位:ms)
* 輸出參數: 無
* 返 回 值: 無
* 其它說明: 無
* 修改日期      版本號       修改人        修改內容
* ------------------------------------------------------------------
* 20160517       V1.0     Zhou Zhaoxiong     創建
********************************************************************/ 
void Sleep(UINT32 iCountMs)
{
    struct timeval t_timeout = {0};

    if (iCountMs < 1000)
    {
        t_timeout.tv_sec  = 0;
        t_timeout.tv_usec = iCountMs * 1000;
    }
    else
    {
        t_timeout.tv_sec  = iCountMs / 1000;
        t_timeout.tv_usec = (iCountMs % 1000) * 1000;
    }
    select(0, NULL, NULL, NULL, &t_timeout);    // 調用select函數阻塞程序
}

程序測試
將編寫好的程序“FileDistribute.c”上傳到Linux機器,並使用“gcc -g -o FileDistribute FileDistribute.c”命令對該程序進行編譯,生成“FileDistribute”文件。下麵對程序進行詳細的測試。

1.在啟動程序之前,在源目錄SourceDir中放入文件File1_1.txt、File2_1.txt和File3_1.txt,程序運行情況如下:

ScanDirAndDistribute:now, mv /home/zhou/zhouzx/TestDir/SourceDir/File1_1.txt /home/zhou/zhouzx/TestDir/FileDir1
ScanDirAndDistribute:now, mv /home/zhou/zhouzx/TestDir/SourceDir/File2_1.txt /home/zhou/zhouzx/TestDir/FileDir2
ScanDirAndDistribute:now, mv /home/zhou/zhouzx/TestDir/SourceDir/File3_1.txt /home/zhou/zhouzx/TestDir/FileDir3
ScanDirAndDistribute:this time,totally moved 3 file(s).

可以看到,源目錄中的三個文件已經沒有了,它們被分別移動到了結果目錄FileDir1、FileDir2和FileDir3中:

~/zhouzx/TestDir/SourceDir> ll
total 0
~/zhouzx/TestDir/FileDir1> ll
-rw------- 1 zhou users 12 2016-05-17 18:58 File1_1.txt
~/zhouzx/TestDir/FileDir2> ll
-rw------- 1 zhou users 12 2016-05-17 18:58 File2_1.txt
~/zhouzx/TestDir/FileDir3> ll
-rw------- 1 zhou users 12 2016-05-17 18:58 File3_1.txt

2.一段時間之後,在源目錄SourceDir中放入文件File4_1.txt,程序運行情況如下:

ScanDirAndDistribute:now, rm /home/zhou/zhouzx/TestDir/SourceDir/File4_1.txt
ScanDirAndDistribute:this time,totally moved 0 file(s).

可以看到,因為前綴不匹配,File4_1.txt文件直接被刪除掉了。

~/zhouzx/TestDir/SourceDir> ll
total 0

3.一段時間之後,在源目錄SourceDir中放入空文件File_7.txt、File_8.txt和File_9.txt,程序運行情況如下:

ScanDirAndDistribute:/home/zhou/zhouzx/TestDir/SourceDir/File_7.txt is an empty file, so delete it directly!
ScanDirAndDistribute:/home/zhou/zhouzx/TestDir/SourceDir/File_8.txt is an empty file, so delete it directly!
ScanDirAndDistribute:/home/zhou/zhouzx/TestDir/SourceDir/File_9.txt is an empty file, so delete it directly!
ScanDirAndDistribute:this time,totally moved 0 file(s).

可以看到,源目錄SourceDir中的空文件已經被全部刪除掉了。

~/zhouzx/TestDir/SourceDir> ll
total 0

需求擴展
基於本文中的需求和程序,可考慮對需求進行以下擴展:
1.在移動(分發)文件之前,先查看相同文件名的文件在對應結果目錄中是否存在,如果存在,則直接將該文件在源目錄中刪除掉;如果不存在,才將該文件移動到對應結果目錄中。

2.為避免結果目錄中的文件過多,可以在程序中添加清理機製,即將存放時間超過一定時長的文件刪除掉。

3.為了體現程序的靈活性,可將部分文件信息(如文件前綴、後綴、存放目錄、掃描間隔時長等)存放到配置文件中,程序在啟動時讀取相關的配置項的值來執行後續目錄掃描和文件分發的操作。

最後更新:2017-10-15 21:33:45

  上一篇:go  怎麼根據現有的網站文件選擇空間和操作係統?
  下一篇:go 除了馬雲演唱,雲棲大會的看點還在於 AI和AR;VR 行業不景氣,諾基亞停止研發 OZO