二進制文件讀寫不進行任何格式轉換,**字節流 1:1 傳輸**,是文件拷貝、序列化、多媒體處理、嵌入式固件升級的核心操作。本文系統講解 fopen 模式、fread/fwrite 參數語義、fseek 定位機制,並給出標準文件拷貝程序與各函數權威參考手冊。
#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 1024
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "Usage: %s infile outfile\n", argv[0]);
return 1;
}
FILE *infile = fopen(argv[1], "rb"); // 二進制讀
FILE *outfile = fopen(argv[2], "wb"); // 二進制寫 (截斷/創建)
if (!infile || !outfile) {
perror("fopen");
return 1;
}
unsigned char buf[MAXLEN];
size_t rc;
while ((rc = fread(buf, 1, MAXLEN, infile)) > 0) {
fwrite(buf, 1, rc, outfile); // 關鍵:寫入實際讀到的字節數 rc
}
fclose(infile);
fclose(outfile);
return 0;
}
fread` 返回**實際讀取項數** (此處項大小=1),EOF 或錯誤返回 0/短計數。fwrite` 必須用 `rc` 作為項數,而非 `MAXLEN`,否則最後一塊會寫入垃圾數據。rb`/`wb` 模式:Windows 下關鍵 (禁用 \r\n 轉換),Linux/Unix 忽略 `b` 但建議保留以提高可移植性。fopen:打開文件流FILE *fopen(const char *path, const char *mode);
| 模式 | 含義 | 文件不存在 | 文件存在 | 指針初始位置 |
|---|---|---|---|---|
| r | 只讀文本 | 失敗 | 保留 | 文件頭 |
| r+ | 讀寫文本 | 失敗 | 保留 | 文件頭 |
| w | 只寫文本 | 創建 | **截斷為 0** | 文件頭 |
| w+ | 讀寫文本 | 創建 | **截斷為 0** | 文件頭 |
| a | 追加文本 | 創建 | 保留 | 文件尾 |
| a+ | 讀追加文本 | 創建 | 保留 | 文件尾 |
| rb/wb/ab/rb+/wb+/ab+ | 對應二進制版本 | 同上 | 同上 | 同上 |
FILE* 成功,NULL 失敗 (檢查 errno)。umask 影響,默認 0666。fread:從流讀取size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
nmemb 個項,每項 size 字節,總計 size*nmemb 字節。nmemb),需配合 feof()/ferror() 區分 EOF 與錯誤。fread(buf, 1, MAXLEN, fp) (項大小 1,項數 = 字節數)。fwrite:寫入流size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
nmemb 項,返回實際寫入項數 (磁盤滿/錯誤時短計數)。setvbuf 控制 (全緩衝/行緩衝/無緩衝)。fseek`:隨機訪問定位int fseek(FILE *stream, long offset, int whence);
| whence | 常量值 | 含義 |
|---|---|---|
| SEEK_SET | 0 | 從文件頭偏移 offset 字節 |
| SEEK_CUR | 1 | 從**當前位置**偏移 offset 字節 |
| SEEK_END | 2 | 從文件尾偏移 offset 字節 (通常負值) |
SEEK_SET 配合 0 或 ftell 返回值,其他行為未定義。ftell:返回長整型偏移 (二進制流為字節數,文本流為魔術值)。fgetpos/fsetpos:使用 fpos_t 不透明類型,支持大文件 (>2GB) 和文本流安全定位。rewind(fp):等價 fseek(fp, 0, SEEK_SET) + clearerr(fp)。二進制 IO 三板斧:正確模式打開 → fread/fwrite 循環配合實際計數 → fseek 隨機定位。記住 rb/wb 可移植性、rc` 回傳值語義、文本/二進制流定位差異,即可駕馭 99% 文件讀寫場景。