处理硬盘文件是C语言基本功。主流方法就两种:标准I/O(stdio.h) 和 系统I/O/低级I/O(unistd.h, fcntl.h)。记住:日常首选标准I/O!系统I/O仅在特定需求时才用。
核心差异一句话:标准I/O有“缓冲区”(预加载数据,效率高),系统I/O是原始字节流操作**(控制精细)。
代码对比直击核心
场景1:打开/关闭文件
// 标准I/O:fopen + fclose (FILE*)
#include <stdio.h>
int main() {
// 打开: "r"(读), "w"(写), "a"(追加), "rb"(读二进制)...
FILE *file = fopen("data.txt", "r");
if (!file) { perror("Error opening file"); return 1; } // 务必检查错误!
// ... 读写操作在此 ...
fclose(file); // 务必关闭! 释放资源 & 刷新缓冲区
return 0;
}
// 系统I/O:open + close (文件描述符 int fd)
#include <fcntl.h> // O_RDONLY, O_WRONLY, O_CREAT
#include <unistd.h>
int main() {
// 打开: O_RDONLY(只读), O_WRONLY|O_CREAT(写+创建), O_APPEND(追加)...
int fd = open("data.bin", O_RDONLY, 0644); // 0644是文件权限(如需要)
if (fd == -1) { perror("Error opening file"); return 1; } // 务必检查错误!
// ... 读写操作在此 ...
close(fd); // 务必关闭! 释放文件描述符
return 0;
}
场景2:读取文本文件(一行)
// 标准I/O:简单读行 (fgets)
char buffer[256];
if (fgets(buffer, sizeof(buffer), file) != NULL) {
printf("Read line: %s", buffer);
} // 缓冲区大小足够,自动处理行尾\n
// 系统I/O:原始读(read) + 自己解析 (更繁琐)
char buffer[256];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1); // -1预留结尾\0位置
if (bytes_read > 0) {
buffer[bytes_read] = '\0'; // 手动加字符串结束符!
// 你可能需要遍历buffer找换行符\n来“切分”行
printf("Read data: %s", buffer);
} else if (bytes_read == 0) { /* EOF */ }
else { perror("Read error"); }
场景3:写入格式化数据到文本文件
// 标准I/O:像printf一样写文件 (fprintf) - 超方便!
int num = 42;
char *text = "Hello";
fprintf(file, "Number: %d\nText: %s\n", num, text); // 自动格式化,带换行
// 系统I/O:需自己拼接格式化字符串 (麻烦!)
char buffer[256];
int num = 42;
char *text = "Hello";
int len = snprintf(buffer, sizeof(buffer), "Number: %d\nText: %s\n", num, text);
if (len >= sizeof(buffer)) { /* 缓冲区溢出风险 */ }
write(fd, buffer, len); // 只写有效部分len, 包含\n
场景4:读写二进制数据(结构体)
// 标准I/O:直接读写整块内存 (fread/fwrite)
struct Data {
int id;
float value;
} myData, readData;
myData.id = 1;
myData.value = 3.14f;
// 写入
fwrite(&myData, sizeof(struct Data), 1, file); // 高效写入整个结构体
// 读取
if (fread(&readData, sizeof(struct Data), 1, file) == 1) {
printf("Read ID: %d, Value: %.2f\n", readData.id, readData.value);
}
// 系统I/O:同样读写字节流 (read/write)
struct Data myData, readData;
myData.id = 1;
myData.value = 3.14f;
// 写入
write(fd, &myData, sizeof(struct Data)); // 直接写内存块
// 读取
ssize_t bytes_read = read(fd, &readData, sizeof(struct Data));
if (bytes_read == sizeof(struct Data)) { /* 成功读取 */ }
核心差异速查表:
特性 | 标准I/O (stdio.h) | 系统I/O (unistd.h) |
代表函数 | fopen, fprintf, fread, fclose | open, read, write, close |
对象 | FILE*(文件指针) | int fd(文件描述符) |
核心优势 | 带缓冲区(高效) | 精细控制(权限/设备/锁) |
关键工具 | 格式化 (fprintf/fscanf) | 原始字节操作 |
错误处理 | 检查返回值(NULL, 0等) | 检查返回值(-1) & errno |
首要选择 | YES! (90%场景) | 特殊需求(设备/控制权) |
选择指南一句话:
- 做文件?用 fopen+ fprintf/fscanf/fread/fwrite+ fclose(标准I/O)!高效又省心!
- 玩设备/搞底层?才轮到 open+ read/write+ close(系统I/O)。
必记忠告:
- 无论用哪种,必须检查函数返回值! 文件操作容易出错。
- 绝对不要忘记关闭文件 (fclose/ close)! 忘记关文件是严重的资源泄漏!