將源目錄中的文件按照前綴分發(fā)到不同目錄中的算法設計及C代碼實現(xiàn)
一、需求描述
在Linux系統(tǒng)的某個源目錄中有一批后綴相同的文件,編寫程序將這些文件按照前綴分發(fā)到不同的目錄中。
例如,源目錄SourceDir中存放有三個后綴相同的文件File1_1.txt、File2_1.txt和File3_1.txt,按照前綴File1_、File2_和File3_將它們分別移動(分發(fā))到目錄FileDir1、FileDir2和FileDir3中。
二、算法設計
基于需求,可以采用如圖1所示的程序流程:
圖1 程序總體流程
三、特殊流程考慮
在編寫程序的過程中,對于某些特殊流程的考慮如下:
1.如果掃描源目錄出錯,則直接停止程序的運行,而不用繼續(xù)掃描下一個目錄。
2.對于某些空文件(即文件的大小為0),直接在源目錄中將其刪除,而不用進行分發(fā)。
3.為了隨時能夠處理放到源目錄中的文件,程序每隔一段時間(如一分鐘)掃描一次源目錄。也就是說,如果不人為操作,程序啟動之后會不停地運行。
四、程序代碼
- /**********************************************************************
- * 版權所有 (C)2016, Zhou Zhaoxiong。
- *
- * 文件名稱:FileDistribute.c
- * 文件標識:無
- * 內容摘要:將某個目錄中的文件按照前綴分發(fā)到對應的目錄中
- * 其它說明:無
- * 當前版本:V1.0
- * 作 者:Zhou Zhaoxiong
- * 完成日期:20160517
- *
- **********************************************************************/
- #include <stdio.h>
- #include <string.h>
- #include <dirent.h>
- #include <ftw.h>
- #include <time.h>
- // 重定義數(shù)據(jù)類型
- typedef signed int INT32;
- typedef unsigned int UINT32;
- typedef unsigned char UINT8;
- // 全局變量定義
- UINT8 g_szSourceDir[256] = {0}; // 源文件的目錄
- // 函數(shù)聲明
- INT32 SelectFlies(struct dirent *pDir);
- void ScanDirAndDistribute(void);
- void Sleep(UINT32 iCountMs);
- /****************************************************************
- * 功能描述: 主函數(shù)
- * 輸入?yún)?shù): 無
- * 輸出參數(shù): 無
- * 返 回 值: 0-執(zhí)行完成
- * 其他說明: 無
- * 修改日期 版本號 修改人 修改內容
- * -------------------------------------------------------------
- * 20160517 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ****************************************************************/
- INT32 main(void)
- {
- // 源文件的目錄
- snprintf(g_szSourceDir, sizeof(g_szSourceDir)-1, "%s/zhouzx/TestDir/SourceDir", getenv("HOME"));
- // 調用函數(shù)執(zhí)行文件的分發(fā)
- while (1)
- {
- ScanDirAndDistribute();
- Sleep(60 * 1000); // 每一分鐘執(zhí)行一次文件的分發(fā)
- }
- return 0;
- }
- /**********************************************************************
- * 功能描述:根據(jù)后綴選擇文件
- * 輸入?yún)?shù):dir-目錄
- * 輸出參數(shù):無
- * 返 回 值:0-失敗 1-成功
- * 其它說明:一個形如test.txt的文件要被掃描出來, 而形如test的文件不符合條件
- * 修改日期 版本號 修改人 修改內容
- * --------------------------------------------------------------------
- * 20160517 V1.0 ZhouZhaoxiong 創(chuàng)建
- ***********************************************************************/
- INT32 SelectFlies(struct dirent *pDir)
- {
- if (pDir == NULL)
- {
- printf("SelectFlies:input parameter is NULL!\n");
- return 0;
- }
- // 根據(jù).txt(后綴)選擇文件
- if (strstr(pDir->d_name, ".txt") != NULL)
- {
- return 1; // 找到了滿足條件的文件
- }
- else
- {
- return 0;
- }
- }
- /**********************************************************************
- * 功能描述:掃描目錄并分發(fā)文件
- * 輸入?yún)?shù):無
- * 輸出參數(shù):無
- * 返 回 值:無
- * 其它說明:無
- * 修改日期 版本號 修改人 修改內容
- * --------------------------------------------------------------------
- * 20160517 V1.0 ZhouZhaoxiong 創(chuàng)建
- ***********************************************************************/
- 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;
- // 掃描源目錄, 并分發(fā)文件
- 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 ++)
- {
- // 先判斷掃描到的文件是否為空文件, 是則直接刪除, 不是才執(zhí)行移動的操作
- 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 // 根據(jù)前綴將文件移動(分發(fā))到對應的目錄中
- {
- 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; // 繼續(xù)判斷下一個
- }
- 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;
- }
- /**********************************************************************
- * 功能描述: 程序休眠
- * 輸入?yún)?shù): iCountMs-休眠時間(單位:ms)
- * 輸出參數(shù): 無
- * 返 回 值: 無
- * 其它說明: 無
- * 修改日期 版本號 修改人 修改內容
- * ------------------------------------------------------------------
- * 20160517 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ********************************************************************/
- 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函數(shù)阻塞程序
- }
五、程序測試
將編寫好的程序“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).
可以看到,源目錄中的三個文件已經(jīng)沒有了,它們被分別移動到了結果目錄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).1212
可以看到,因為前綴不匹配,F(xiàn)ile4_1.txt文件直接被刪除掉了。
- ~/zhouzx/TestDir/SourceDir> ll
- total 01212
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中的空文件已經(jīng)被全部刪除掉了。
- ~/zhouzx/TestDir/SourceDir> ll
- total 01212
六、需求擴展
基于本文中的需求和程序,可考慮對需求進行以下擴展:
1.在移動(分發(fā))文件之前,先查看相同文件名的文件在對應結果目錄中是否存在,如果存在,則直接將該文件在源目錄中刪除掉;如果不存在,才將該文件移動到對應結果目錄中。
2.為避免結果目錄中的文件過多,可以在程序中添加清理機制,即將存放時間超過一定時長的文件刪除掉。
3.為了體現(xiàn)程序的靈活性,可將部分文件信息(如文件前綴、后綴、存放目錄、掃描間隔時長等)存放到配置文件中,程序在啟動時讀取相關的配置項的值來執(zhí)行后續(xù)目錄掃描和文件分發(fā)的操作。
【本文是51CTO專欄作者周兆熊的原創(chuàng)文章,作者微信公眾號:周氏邏輯(logiczhou)】