CStdioFile::ReadString 逐行讀入 CString 緩衝區sscanf 依格式字串解析欄位,自動忽略任意數量空白關鍵優勢:sscanf 對格式極度寬容——欄位間可有任意空白、Tab、行首行尾空白皆可正確解析。
VC6.0 → MFC AppWizard (exe) → Single Document → 專案名 ReadCoordinate。
// ReadCoordinateView.h
class CReadCoordinateView : public CView {
// ...
public:
CArray<CPoint, CPoint> m_PointArray; // 座標點陣列
int m_PointNum; // 點數
// 建構子初始化 m_PointNum = 0
};
// ReadCoordinateView.cpp
void CReadCoordinateView::OnReadData() {
CFileDialog dlg(TRUE, _T("txt"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
_T("文字檔 (*.txt)|*.txt|所有檔案 (*.*)|*.*||"));
if (dlg.DoModal() != IDOK) return;
CStdioFile file;
if (!file.Open(dlg.GetPathName(), CFile::modeRead | CFile::typeText)) {
AfxMessageBox(_T("無法開啟檔案"));
return;
}
CString line;
char temp1[32], temp2[32];
// 讀第一行:點數
if (!file.ReadString(line)) return;
memset(temp1, 0, sizeof(temp1));
sscanf(line, "%s", temp1);
m_PointNum = atoi(temp1);
m_PointArray.RemoveAll();
// 逐行讀取座標
for (int i = 0; i < m_PointNum && file.ReadString(line); ++i) {
memset(temp1, 0, sizeof(temp1));
memset(temp2, 0, sizeof(temp2));
if (sscanf(line, "%s %s", temp1, temp2) == 2) {
int x = atoi(temp1);
int y = atoi(temp2);
m_PointArray.Add(CPoint(x, y));
}
}
file.Close();
// 繪圖顯示
CDC* pDC = GetDC();
for (int i = 0; i < m_PointNum - 1; ++i) {
pDC->MoveTo(m_PointArray[i]);
pDC->LineTo(m_PointArray[i + 1]);
}
ReleaseDC(pDC);
}
5
10 20
30 40
45 85
100 120
200 300
以下格式同樣可正確解析:
5
10 20
30 40
45 85
100 120
200 300
// 浮點數座標
double x, y;
sscanf(line, "%lf %lf", &x, &y);
// 多欄位:ID, X, Y, Z, Label
int id; double x, y, z; char label[64];
sscanf(line, "%d %lf %lf %lf %s", &id, &x, &y, &z, label);
// CSV 逗號分隔
sscanf(line, "%d,%lf,%lf,%lf,%[^,]", &id, &x, &y, &z, label);
| 場景 | 建議做法 |
|---|---|
| 超大檔案 (>100MB) | 改用 CFile + 手動緩衝區,避免 CString 記憶體壓力 |
| 編碼非 ANSI | 讀入後用 MultiByteToWideChar 轉 Unicode,或直接用 CStdioFile Unicode 版本 (VS2005+) |
| 異常行處理 | 檢查 sscanf 回傳值 (成功轉換欄位數),記錄錯誤行號並跳過 |
| 高頻讀寫 | 考慮記憶體對應檔案 CreateFileMapping |
CStdioFile + sscanf 是 VC++ 讀取結構化文字檔的黃金組合:程式碼極簡、格式寬容、效能足夠、無外部依賴。掌握此法,輕鬆應對地質座標、感測器日誌、CSV 匯入等實務需求。