延續前兩篇,本文聚焦於輸入輸出錯誤檢查、臨時檔案安全、目錄操作選型、I/O效能優化、記憶體管理等進階實戰技巧,助你寫出更健壯、高效的C程式。
原則:每次呼叫I/O函數(fread, fwrite, fprintf 等)後,立即檢查 ferror()。因同一檔案每次操作都會產生新的 ferror 值,延遲檢查會導致錯誤資訊丟失。
FILE *fp = fopen("data.bin", "wb");
if (!fp) return -1;
fwrite(buf, 1, len, fp);
if (ferror(fp)) { /* 立即處理錯誤 */ }
fclose(fp);
使用臨時檔案(tmpfile(), mkstemp())時必須解決兩個核心問題:
mkstemp 模板),避免手動拼接檔名。0600 權限(僅擁有者讀寫),防止其他使用者竊讀、刪除、修改。mkstemp 預設即如此。char tmpl[] = "/tmp/myprog_XXXXXX";
int fd = mkstemp(tmpl); // 原子建立,返回唯一檔案描述符
if (fd == -1) { /* 處理錯誤 */ }
// 使用 fd 進行讀寫...
close(fd);
unlink(tmpl); // 關閉後自動刪除(若在close前unlink,檔案關閉時釋放空間)
何時使用目錄(檔案系統),何時上資料庫?考量五個維度:
| 維度 | 適用目錄/檔案 | 適用資料庫 |
|---|---|---|
| 資料量 | 小型、離散資料 | 大量結構化資料 |
| 資料類型 | 屬性、配置、小型二進位物件 | 關聯性強、頻繁查詢更新的記錄 |
| 讀寫比 | 讀多寫少 | 大量寫入/更新 |
| 搜尋需求 | 簡單路徑查找 | 複雜條件檢索、索引 |
| 標準存取 | POSIX API | SQL/ODBC/JDBC |
實踐建議:目錄存指標(檔名、路徑),大檔案存檔案系統,元資料存資料庫。
rmdir() 僅能刪除空目錄。非空目錄需遞歸刪除子項(ftw + unlink/rmdir)或使用系統命令 system("rm -rf")(注意注入風險)。DELTREE / Linux rm -rf 會強制刪除整棵目錄樹(含隱藏、唯讀檔案),慎用。fnmerge() 組合完整路徑前,務必先驗證磁碟機與父目錄是否存在,避免建立失敗。user_count 而非 a)。i < N 而非 i <= N)。free(ptr); ptr = NULL; 防止野指標與重複釋放。a[i])而非指標算術(*(a+i)),雖微增指令數但大幅提升可讀性。assert(ptr != NULL)。int*),而非 int。***ptr),除非極少數演算法必要,否則嚴重降低可讀性。良好的習慣不僅是規範,更是減少Bug、提升維護性的利器。將上述原則內化為肌肉記憶,你的C代碼將更安全、更專業。