open()系统调用中O_TRUNC未实际清空文件内容的问题
解决O_TRUNC未清空文件导致写入后残留内容的问题
嘿,我太懂你这个坑了!当初我第一次用O_TRUNC参数的时候也踩过类似的雷,看到文件里残留的字符简直一脸懵。咱们来拆解一下问题到底出在哪,以及怎么解决:
问题根源
你看到最终文件是81而不是预期的8,核心原因是:O_TRUNC的作用是在打开文件的瞬间就把整个文件内容清空,但你的操作逻辑应该是先打开文件读取原有内容(这时候没加O_TRUNC,所以文件内容还在),然后直接写入新值——这种情况下,新写入的内容只会覆盖文件开头对应长度的字节,剩下的原有字符自然就保留下来了。
举个例子:原文件是11(两个字节),你写入8(一个字节),只会把第一个1改成8,第二个1还留在文件里,所以结果就是81。
两种解决方案
方案一:分两步读写(最安全推荐)
先以只读模式打开文件读取内容,关闭后再以清空模式打开写入新值,这样能彻底避免残留问题:
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> int main() { // 1. 读取原有内容 int fd_read = open("test.txt", O_RDONLY); if (fd_read == -1) { perror("打开读取文件失败"); return 1; } char buf[10]; ssize_t bytes_read = read(fd_read, buf, sizeof(buf)-1); close(fd_read); if (bytes_read <= 0) { perror("读取文件失败"); return 1; } buf[bytes_read] = '\0'; // 确保字符串正确终止 // 计算新数值 int num = atoi(buf) - 3; // 2. 清空并写入新内容 int fd_write = open("test.txt", O_WRONLY | O_TRUNC | O_CREAT, 0644); if (fd_write == -1) { perror("打开写入文件失败"); return 1; } char write_buf[10]; int len = snprintf(write_buf, sizeof(write_buf), "%d", num); write(fd_write, write_buf, len); close(fd_write); return 0; }
方案二:单文件描述符操作(适合需保持文件打开的场景)
如果必须用同一个文件描述符完成读写,可以在读取内容后,用ftruncate()手动清空文件,再定位到开头写入:
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> int main() { int fd = open("test.txt", O_RDWR); if (fd == -1) { perror("打开文件失败"); return 1; } // 读取原有内容 char buf[10]; ssize_t bytes_read = read(fd, buf, sizeof(buf)-1); if (bytes_read <= 0) { perror("读取文件失败"); close(fd); return 1; } buf[bytes_read] = '\0'; int num = atoi(buf) - 3; // 清空文件并移动到开头 if (ftruncate(fd, 0) == -1) { perror("清空文件失败"); close(fd); return 1; } lseek(fd, 0, SEEK_SET); // 写入新内容 char write_buf[10]; int len = snprintf(write_buf, sizeof(write_buf), "%d", num); write(fd, write_buf, len); close(fd); return 0; }
关键注意点
- 千万别用
O_RDWR | O_TRUNC打开文件来同时读写——O_TRUNC会在打开瞬间清空文件,你根本读不到原来的内容。 - 只要新写入的内容长度比原文件短,就必须主动清空或截断文件,否则一定会残留旧内容。
内容的提问来源于stack exchange,提问作者Sebastian Oliva
相关产品推荐
相关产品推荐

