設定檔語法設計
// 註解
// 協定名稱: TL
// 工程: SQ
#DEFINE_BEGIN // 單值參數區塊開始
@COM_PORT .COM1 // 鍵值以空白/Tab 分隔,行尾可接註解
@COM_BAUDRATE 1200
@STATIONNO 0
#DEFINE_END
#TABLE_BEGIN // 表格區塊
// ID 識別字串 欄位以 空白/Tab/逗號 分隔,字串內空白保留
0 Ion Detector, ALU1, L1S43
1 Thermal Det, ALU1, L1S39
#TABLE_END
語法規則摘要
- 單行註解:
//;
- 區塊標記:
#DEFINE_BEGIN/END、#TABLE_BEGIN/END;
- 單值:
@KEY VALUE,分隔符 space/tab;
- 表格:第一欄整數 ID,之後欄位
space/tab/comma 分隔,**字串內空白保留**;
- 檔案 < 48KB,表格 ≤ 100 行 × 4 欄 (含 ID)。
C++ 封裝類 CDataTxt
資料結構
#define TABLE_MAXROW 100
#define TABLE_MAXCOL 5
struct TableRec {
int nID;
char s[TABLE_MAXCOL-1][64]; // 除 ID 外欄位
};
class CDataTxt {
public:
CDataTxt(); ~CDataTxt();
CString m_szPath; // 設定檔完整路徑
BOOL Read(); // 讀入並解析
BOOL GetDefine(LPCTSTR key, CString& val); // 取單值
TableRec m_Table[TABLE_MAXROW];
int m_nRows;
private:
char m_cbuf[1024*48]; // 原始檔案緩衝
int m_nBufSize, m_nDataSize;
CString m_szDefine, m_szTable; // 區塊文字
int m_nDefineLen, m_nTableLen;
void DelNote(); // 移除註解
void FormatTable(); // 正規化表格分隔
};
核心解析邏輯 (節錄)
BOOL CDataTxt::Read() {
CFile fl;
if (!fl.Open(m_szPath, CFile::modeRead|CFile::typeBinary)) return FALSE;
m_nDataSize = fl.Read(m_cbuf, m_nBufSize);
fl.Close();
m_cbuf[m_nDataSize] = '\0';
// 1. 移除註解
DelNote();
// 2. 擷取 #DEFINE_BEGIN ... #DEFINE_END 區塊
// 簡易實現:strstr 定位 → 子字串 → m_szDefine
// 3. 擷取 #TABLE_BEGIN ... #TABLE_END → m_szTable
// 4. 解析單值區塊
// 每行 @KEY VALUE → 存入 map 或線性搜尋
// 5. 解析表格區塊
FormatTable(); // 統一分隔符為 \t
// 逐行 sscanf: "%d %63[^\t] %63[^\t] %63[^\t] %63[^\n]"
// 填入 m_Table[m_nRows++]
return TRUE;
}
void CDataTxt::DelNote() {
char* p = m_cbuf;
while (*p) {
if (p[0]=='/' && p[1]=='/') {
// 找到行尾或檔尾
char* eol = strchr(p, '\n');
if (!eol) eol = p + strlen(p);
memmove(p, eol, strlen(eol)+1); // 覆蓋刪除
} else p++;
}
}
void CDataTxt::FormatTable() {
// 將逗號、多空白/Tab 統一為單一 Tab
// 便於 sscanf 固定格式解析
}
單值查詢
BOOL CDataTxt::GetDefine(LPCTSTR key, CString& val) {
// 在 m_szDefine 中逐行比對 @KEY
// 找到 → 取 VALUE 部分 → val = VALUE; return TRUE;
return FALSE;
}
使用範例
CDataTxt cfg;
cfg.m_szPath = _T("SQTL.txt");
if (cfg.Read()) {
CString port, baud;
cfg.GetDefine(_T("@COM_PORT"), port); // → ".COM1"
cfg.GetDefine(_T("@COM_BAUDRATE"), baud); // → "1200"
for (int i=0; i
擴展建議
- 改用
std::unordered_map 存單值,查詢 O(1);
- 表格欄位數動態:改用
vector>;
- 支援區塊巢狀 / 多檔案
#include;
- 加入型別轉換輔助:
GetInt/GetFloat/GetBool;
- 寫入功能:
Write() 依原格式輸出,保留註解與排版。