檔案操作是 C 語言系統程式設計的基石。本文將從零開始,完整實作一套跨平台的檔案操作函式庫,涵蓋開啟、讀寫、定位、關閉等核心功能,並處理錯誤碼、資源洩漏等工程級細節。
#ifndef FILE_OPS_H #define FILE_OPS_H #include#include /* 檔案模式旗標 */ typedef enum { FILE_READ = 0x01, // 唯讀 FILE_WRITE = 0x02, // 唯寫(截斷) FILE_APPEND = 0x04, // 附加 FILE_BINARY = 0x08 // 二進位模式 } FileMode; /* 檔案控制結構(不透明指標) */ typedef struct FileHandle FileHandle; /* 開啟檔案 */ FileHandle* file_open(const char* path, FileMode mode); /* 關閉檔案 */ int file_close(FileHandle* handle); /* 讀取資料 */ size_t file_read(FileHandle* handle, void* buffer, size_t size); /* 寫入資料 */ size_t file_write(FileHandle* handle, const void* buffer, size_t size); /* 取得檔案大小 */ long file_size(FileHandle* handle); /* 設定讀寫位置 */ int file_seek(FileHandle* handle, long offset, int whence); /* 取得目前位置 */ long file_tell(FileHandle* handle); /* 取得最後錯誤訊息 */ const char* file_strerror(int errnum); #endif
#include "file_ops.h" #include#include #include struct FileHandle { FILE* fp; char* path; FileMode mode; }; static const char* mode_to_stdio(FileMode mode) { static char buf[4]; char* p = buf; if (mode & FILE_READ) *p++ = 'r'; if (mode & FILE_WRITE) *p++ = 'w'; if (mode & FILE_APPEND) *p++ = 'a'; if (mode & FILE_BINARY) *p++ = 'b'; *p = '\0'; return buf; } FileHandle* file_open(const char* path, FileMode mode) { if (!path) return NULL; FileHandle* h = (FileHandle*)malloc(sizeof(FileHandle)); if (!h) return NULL; h->fp = fopen(path, mode_to_stdio(mode)); if (!h->fp) { free(h); return NULL; } h->path = strdup(path); h->mode = mode; return h; } int file_close(FileHandle* handle) { if (!handle) return -1; int ret = 0; if (handle->fp) ret = fclose(handle->fp); free(handle->path); free(handle); return ret; } size_t file_read(FileHandle* handle, void* buffer, size_t size) { if (!handle || !handle->fp || !buffer) return 0; return fread(buffer, 1, size, handle->fp); } size_t file_write(FileHandle* handle, const void* buffer, size_t size) { if (!handle || !handle->fp || !buffer) return 0; return fwrite(buffer, 1, size, handle->fp); } long file_size(FileHandle* handle) { if (!handle || !handle->fp) return -1; long cur = ftell(handle->fp); fseek(handle->fp, 0, SEEK_END); long sz = ftell(handle->fp); fseek(handle->fp, cur, SEEK_SET); return sz; } int file_seek(FileHandle* handle, long offset, int whence) { if (!handle || !handle->fp) return -1; return fseek(handle->fp, offset, whence); } long file_tell(FileHandle* handle) { if (!handle || !handle->fp) return -1; return ftell(handle->fp); } const char* file_strerror(int errnum) { return strerror(errnum); }
#include "file_ops.h" #includeint main() { FileHandle* f = file_open("demo.txt", FILE_WRITE | FILE_BINARY); if (!f) { perror("open"); return 1; } const char* msg = "Hello, File Ops!\n"; file_write(f, msg, strlen(msg)); file_close(f); f = file_open("demo.txt", FILE_READ | FILE_BINARY); if (!f) { perror("open"); return 1; } char buf[128]; size_t n = file_read(f, buf, sizeof(buf)-1); buf[n] = '\0'; printf("Read: %s", buf); file_close(f); return 0; }
__attribute__((cleanup)) 自動關閉檔案。_fseeki64/_ftelli64,Linux 使用 fseeko/ftello。封裝標準 C 庫的檔案操作,不僅能統一跨平台介面,更能在專案中強制統一錯誤處理與資源釋放規範。建議將此模組納入團隊基礎設施庫,並配合靜態分析工具檢查資源洩漏。