首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Linux 目錄監控與統計文件生成:C 語言實現非阻塞掃描、增量解析與持久化控制文件

     編輯:關於C語言

需求場景

  • 源目錄持續產生文件 (命名前綴 Test_)
  • 文件格式:主叫|被叫|開始時間|結束時間| (管道分隔)
  • 需實時生成控制文件 CtlFile.txt:最早開始時間|最晚結束時間|總記錄數|
  • 處理完成文件移至備份目錄,避免重複處理
  • 定期掃描 (每分鐘),長期運行

系統架構設計

┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│  SrcFile/   │────▶│  C 程式常駐  │────▶│ CtlFile/    │
│  Test_*.txt │     │  掃描→解析→統計 │     │ CtlFile.txt │
└─────────────┘     └──────────────┘     └─────────────┘
                           │
                           ▼
                    ┌──────────────┐
                    │ SrcFile_bak/ │
                    │  已處理文件  │
                    └──────────────┘

核心模塊劃分 (三文件結構)

文件職責關鍵函數
main.c入口、初始化、主循環main()
CtlFileCreate.h數據結構、類型定義、函數聲明T_SrcFileContent, GetValueFromStr...
CtlFileCreate.c核心邏輯實現ReadSrcFileAndWriteCtlFile, GetSrcFileFieldValue...

關鍵數據結構

// 源文件單條記錄
typedef struct {
    UINT8 szSrcNumber[50];   // 主叫
    UINT8 szDstNumber[50];   // 被叫
    UINT8 szDataStartTime[50]; // 開始時間
    UINT8 szDataEndTime[50];   // 結束時間
} T_SrcFileContent;

// 全局統計狀態
UINT8 g_szDataStartTime[50] = {0};  // 全域最早開始時間
UINT8 g_szDataEndTime[50] = {0};    // 全域最晚結束時間
UINT32 g_iRecordsSum = 0;           // 總記錄數

核心算法邏輯

1. 字段提取 (通用分隔符解析)

BOOL GetValueFromStr(UINT16 iSerialNum, UINT8 iContentType, 
                     UINT8 *pSourceStr, UINT8 *pDstStr, 
                     UINT8 cIsolater, UINT32 iDstStrSize) {
    // 定位第 iSerialNum 個字段 (以 cIsolater 分隔)
    UINT8 *pStrBegin = pSourceStr;
    while (--iSerialNum) {
        pStrBegin = strchr(pStrBegin, cIsolater);
        if (!pStrBegin) return FALSE;
        pStrBegin++;
    }
    UINT8 *pStrEnd = strchr(pStrBegin, cIsolater);
    if (!pStrEnd) return FALSE;
    
    // 複製字段內容
    UINT32 len = pStrEnd - pStrBegin;
    UINT8 szRetBuf[1024];
    memcpy(szRetBuf, pStrBegin, len);
    szRetBuf[len] = '\0';
    
    // 類型轉換
    switch (iContentType) {
        case MML_STR_TYPE: strncpy(pDstStr, szRetBuf, iDstStrSize); break;
        case MML_INT32_TYPE: *(UINT32*)pDstStr = atoi(szRetBuf); break;
        // ... INT8, INT16
    }
    return TRUE;
}

2. 增量統計更新

void GetCtlFileContentAndWrite(T_SrcFileContent *src, UINT8 *buf) {
    // 更新最早開始時間
    if (strlen(g_szDataStartTime) == 0 || 
        strcmp(g_szDataStartTime, src->szDataStartTime) > 0) {
        strcpy(g_szDataStartTime, src->szDataStartTime);
    }
    
    // 更新最晚結束時間
    if (strlen(g_szDataEndTime) == 0 || 
        strcmp(g_szDataEndTime, src->szDataEndTime) < 0) {
        strcpy(g_szDataEndTime, src->szDataEndTime);
    }
    
    // 總數累加
    g_iRecordsSum++;
    
    // 格式化輸出
    snprintf(buf, 500, "%s|%s|%d|", 
             g_szDataStartTime, g_szDataEndTime, g_iRecordsSum);
}

3. 主掃描循環

void ReadSrcFileAndWriteCtlFile() {
    while (1) {
        DIR *dir = opendir(g_szSourceDir);
        struct dirent *ent;
        while ((ent = readdir(dir))) {
            if (strncmp(ent->d_name, "Test_", 5) == 0) {
                char fullpath[500];
                snprintf(fullpath, sizeof(fullpath), "%s/%s", 
                         g_szSourceDir, ent->d_name);
                
                GetSrcFileContentAndWriteCtlFile(fullpath);
                
                // 移動到備份目錄 (原子操作)
                char cmd[500];
                snprintf(cmd, sizeof(cmd), "mv %s %s", fullpath, g_szSourceBakDir);
                system(cmd);
            }
        }
        closedir(dir);
        Sleep(60 * 1000);  // 休眠 1 分鐘
    }
}

4. 文件行解析流程

void GetSrcFileContentAndWriteCtlFile(char *filename) {
    FILE *fp = fopen(filename, "r");
    char line[1024];
    T_SrcFileContent record;
    
    while (fgets(line, sizeof(line), fp)) {
        RemoveLineEnd(line);  // 去除 \r\n
        if (strlen(line) == 0) continue;
        
        GetSrcFileFieldValue(line, &record);  // 解析 4 個字段
        
        char ctl_line[500];
        GetCtlFileContentAndWrite(&record, ctl_line);  // 更新統計
        WriteToCtlFile(ctl_line);  // 覆寫控制文件
    }
    fclose(fp);
}

編譯與部署

# 編譯
gcc -g -o CtlFileCreate main.c CtlFileCreate.c

# 目錄結構準備
mkdir -p ~/zhouzhaoxiong/zzx/CtlFileCreate/{SrcFile,CtlFile,SrcFile_bak}

# 投放測試文件到 SrcFile/
# 運行
./CtlFileCreate &

# 查看結果
cat ~/zhouzhaoxiong/zzx/CtlFileCreate/CtlFile/CtlFile.txt
# 輸出示例: 20151101 110909|20160109 091545|5|

關鍵設計亮點

特性實現方式價值
增量處理全局變量維護最值、計數O(1) 更新,無需全量重算
去重保障處理後 mv 到備份目錄原子移動,避免重複處理/數據丟失
容錯設計fopen 失敗重試、字段解析邊界檢查生產環境穩健運行
配置外部化路徑、前綴、間隔可改為配置文件無需重編譯適應環境變化
跨平台類型UINT8/UINT32 等自定義類型消除平台差異

改進建議

  1. inotify 替換輪詢:Linux 內核事件通知,毫秒級響應,零 CPU 空轉
  2. 配置文件化:路徑、間隔、前綴移至 INI/JSON 配置
  3. 日誌系統:引入 syslog 或輕量日誌庫,分級記錄
  4. 信號處理:捕獲 SIGTERM/SIGINT 優雅關閉 (刷新緩衝、釋放資源)
  5. 並發安全:若多實例運行,需文件鎖 (flock) 保護控制文件寫入
  6. 時間解析:將字串時間轉為 time_t 比較,避免字典序陷阱 (如 20151103 vs 20151201)
  7. 單元測試:針對 GetValueFromStr、時間比較、邊界條件編寫測試
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved