You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言更新二进制文件时,如何避免数据误导及残留字节问题?

二进制文件更新时清除残留字节的解决方案

问题场景

我们需要在二进制文件student.dat中记录或更新学生数据,学生结构体定义如下:

typedef struct student{
    int roll;
    char name[25];
}stu;

当使用rb+模式打开文件更新现有数据时,若新写入的字节数少于原有数据长度,仅会覆盖对应长度的内容,剩余旧字节会残留(比如原有29字节,新写25字节,剩余4字节残留),这可能导致数据读取错误或误导。

已知提取数据后以wb模式重写、使用临时文件等方法可行,但流程繁琐。以下是无需重新打开文件即可清除残留字节或清空文件的方案:

无需重新打开文件的解决方案

核心思路是利用文件截断函数,在写入新数据后将文件长度截断到当前写入位置,直接清除后续残留字节;若要清空整个文件,可先截断文件长度至0,再写入新内容。

1. POSIX系统(Linux、macOS等):使用ftruncate函数

ftruncate属于POSIX标准库函数,可将文件截断至指定长度,需结合fileno获取文件描述符使用。

示例代码:

#include <stdio.h>
#include <unistd.h>
#include <errno.h>

typedef struct student{
    int roll;
    char name[25];
}stu;

int main() {
    FILE *fp = fopen("student.dat", "rb+");
    if (!fp) {
        perror("Failed to open file");
        return 1;
    }

    // 写入新的学生数据
    stu updated_stu = {103, "Bob Smith"};
    size_t written = fwrite(&updated_stu, sizeof(stu), 1, fp);
    if (written != 1) {
        perror("Failed to write data");
        fclose(fp);
        return 1;
    }

    // 获取当前文件指针位置(即新数据的末尾)
    long new_end_pos = ftell(fp);
    if (new_end_pos == -1) {
        perror("Failed to get file position");
        fclose(fp);
        return 1;
    }

    // 截断文件到新数据末尾,清除残留字节
    if (ftruncate(fileno(fp), new_end_pos) == -1) {
        perror("Failed to truncate file");
        fclose(fp);
        return 1;
    }

    fclose(fp);
    return 0;
}

2. Windows系统:使用_chsize函数

_chsize是微软提供的扩展函数,功能与ftruncate类似,用于调整文件长度,需包含<io.h>头文件。

示例代码:

#include <stdio.h>
#include <io.h>
#include <errno.h>

typedef struct student{
    int roll;
    char name[25];
}stu;

int main() {
    FILE *fp = fopen("student.dat", "rb+");
    if (!fp) {
        perror("Failed to open file");
        return 1;
    }

    // 写入新的学生数据
    stu updated_stu = {103, "Bob Smith"};
    size_t written = fwrite(&updated_stu, sizeof(stu), 1, fp);
    if (written != 1) {
        perror("Failed to write data");
        fclose(fp);
        return 1;
    }

    // 获取当前文件指针位置
    long new_end_pos = ftell(fp);
    if (new_end_pos == -1) {
        perror("Failed to get file position");
        fclose(fp);
        return 1;
    }

    // 截断文件到新数据末尾
    if (_chsize(fileno(fp), new_end_pos) == -1) {
        perror("Failed to truncate file");
        fclose(fp);
        return 1;
    }

    fclose(fp);
    return 0;
}

3. 清空整个文件内容(无需重新打开)

若需要完全清空文件再写入新数据,可在打开rb+后,先将文件指针移到开头,再截断文件长度至0,最后写入新内容:

// 定位到文件开头
fseek(fp, 0, SEEK_SET);
// 截断文件长度为0,清空内容
#ifdef _WIN32
_chsize(fileno(fp), 0);
#else
ftruncate(fileno(fp), 0);
#endif
// 写入新数据
fwrite(&new_stu, sizeof(stu), 1, fp);

注意事项

  • ftruncate和_chsize仅对已打开的文件有效,无需重新打开文件即可调整长度。
  • 使用这些函数前需确保文件已成功打开,且拥有写入权限。
  • 跨平台开发时,需通过宏定义区分POSIX和Windows环境,保证代码兼容性。

内容的提问来源于stack exchange,提问作者Mildred Gallagher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 12:37:39