fopen 本質是向作業系統請求檔案控制代碼,**不限制副檔名**。任何檔案(.txt、.docx、.jpg、.exe、.mp4)皆可開啟,差別在於:
"r", "w"):自動處理換行符轉換(Windows CRLF ↔ LF),**僅適用純文字檔**。"rb", "wb", "rb+"):**位元組級原始存取**,不做任何轉換,**適用所有檔案格式**。| 檔案類型 | 內部結構複雜度 | 手寫解析器難度 | 成熟庫/工具 |
|---|---|---|---|
| 純文字 (.txt, .csv, .json, .xml) | 低(行基礎、分隔符) | 低 | 標準庫、RapidJSON、TinyXML |
| Office 文件 (.docx, .xlsx, .pptx) | 極高(ZIP 容器 + XML + 關聯) | 極高 | Apache POI, libxml2, python-docx, EPPlus |
| 圖片 (.jpg, .png, .bmp, .gif) | 中高(標頭、壓縮演算法、色彩空間) | 高 | libjpeg, libpng, stb_image, OpenCV, ImageMagick |
| 音訊/影片 (.mp3, .mp4, .wav) | 極高(容器格式、編解碼器、串流同步) | 極高 | FFmpeg, libav, GStreamer, Media Foundation |
| 資料庫 (.sqlite, .mdb) | 高(B-tree、頁面管理、事務日誌) | 極高 | SQLite, LevelDB, RocksDB |
#include <stdio.h>
#include <stdint.h>
#pragma pack(push, 1)
typedef struct {
uint16_t signature; // "BM"
uint32_t file_size;
uint16_t reserved1;
uint16_t reserved2;
uint32_t data_offset;
} BMPFileHeader;
typedef struct {
uint32_t header_size;
int32_t width;
int32_t height;
uint16_t planes;
uint16_t bits_per_pixel;
uint32_t compression;
uint32_t image_size;
int32_t x_pixels_per_meter;
int32_t y_pixels_per_meter;
uint32_t colors_used;
uint32_t colors_important;
} BMPInfoHeader;
#pragma pack(pop)
int main() {
FILE *fp = fopen("test.bmp", "rb");
if (!fp) { perror("fopen"); return 1; }
BMPFileHeader fh;
BMPInfoHeader ih;
fread(&fh, sizeof(fh), 1, fp);
fread(&ih, sizeof(ih), 1, fp);
if (fh.signature == 0x4D42) { // 'BM'
printf("BMP 檔案: %dx%d, %d bits, 檔案大小 %u bytes\n",
ih.width, ih.height, ih.bits_per_pixel, fh.file_size);
} else {
printf("非 BMP 檔案\n");
}
fclose(fp);
return 0;
}
關鍵點:"rb" 模式、#pragma pack(1) 取消對齊、fread 直接讀入結構體。
| 模式 | 檔案存在 | 檔案不存在 | 定位 | 適用場景 |
|---|---|---|---|---|
"wb" | 截斷為 0 長度 | 建立新檔 | 開頭 | 寫入新資料、覆蓋 |
"ab" | 保留內容 | 建立新檔 | 結尾 | 日誌追加、資料流寫入 |
"rb+" | 保留內容 | 失敗 (NULL) | 開頭 | 隨機讀寫現有檔案 |
"wb+" | 截斷 | 建立新檔 | 開頭 | 建立並隨機讀寫 |
"ab+" | 保留 | 建立新檔 | 結尾 | 追加並可回頭讀取 |
fopen 預設文字模式會轉換 \r\n ↔ \n,**二進位檔必須加 b**。b 無影響但建議加上以明確語意、增強可移植性。fopen64 / _fseeki64 / _ftelli64 或編譯選項 -D_FILE_OFFSET_BITS=64。_wfopen (wchar_t*);跨平台建議用 C++17 std::filesystem + std::fstream。// C++17 標準庫
#include <fstream>
#include <filesystem>
std::ifstream file("image.jpg", std::ios::binary);
if (file) {
file.seekg(0, std::ios::end);
size_t size = file.tellg();
file.seekg(0);
std::vector<char> buffer(size);
file.read(buffer.data(), size);
// 處理 buffer...
}
優點:RAII 自動關閉、型別安全、例外處理、支援 std::filesystem::path 跨平台路徑。
fopen 配合 二進位模式 ("rb"/"wb") 可開啟**任何格式**檔案進行位元組級存取。但**複雜格式(Office、多媒體、資料庫)務必使用成熟庫**,勿嘗試手寫解析器。現代 C++ 專案優先考慮 std::fstream、memory_mapped_file (Boost/Win32/mmap) 以獲得更安全、可維護的程式碼。