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

如何通过WinAPI的CreateFile()和WriteFile()在文件开头追加数据?

实现WinAPI将数据追加到文件开头的解决方案

方法一:内存中转法(适合小文件)

直接读取原文件内容到内存,先写入新数据,再追加原内容,步骤简单高效:

  • 以读写权限打开目标文件(不存在则创建)
  • 读取原文件全部内容到内存
  • 将文件指针移至开头,写入新数据
  • 接着写入原文件内容
  • 清理资源

代码示例:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    // 打开目标文件,支持读写,不存在则创建
    HANDLE hFile = CreateFile(
        L"target.txt",
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ,
        NULL,
        OPEN_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );

    if (hFile == INVALID_HANDLE_VALUE) {
        printf("打开文件失败,错误码:%d\n", GetLastError());
        return 1;
    }

    DWORD fileSize = GetFileSize(hFile, NULL);
    char* pOldContent = NULL;
    DWORD bytesRead = 0;

    // 文件非空时读取原内容
    if (fileSize != 0 && fileSize != INVALID_FILE_SIZE) {
        pOldContent = (char*)malloc(fileSize);
        if (!pOldContent) {
            printf("内存分配失败\n");
            CloseHandle(hFile);
            return 1;
        }

        if (!ReadFile(hFile, pOldContent, fileSize, &bytesRead, NULL)) {
            printf("读取原文件失败,错误码:%d\n", GetLastError());
            free(pOldContent);
            CloseHandle(hFile);
            return 1;
        }
    }

    // 定位到文件开头,写入新数据
    SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
    const char* newData = "这是要追加到开头的新内容\n";
    DWORD bytesWritten;

    if (!WriteFile(hFile, newData, strlen(newData), &bytesWritten, NULL)) {
        printf("写入新数据失败,错误码:%d\n", GetLastError());
        if (pOldContent) free(pOldContent);
        CloseHandle(hFile);
        return 1;
    }

    // 写入原文件内容(如果存在)
    if (pOldContent && bytesRead > 0) {
        if (!WriteFile(hFile, pOldContent, bytesRead, &bytesWritten, NULL)) {
            printf("写入原内容失败,错误码:%d\n", GetLastError());
        }
    }

    // 清理资源
    if (pOldContent) free(pOldContent);
    CloseHandle(hFile);
    return 0;
}

方法二:临时文件中转法(适合大文件)

避免一次性读取大文件占用过多内存,通过临时文件先写入新数据,再追加原文件内容,最后替换原文件:

  • 创建临时文件
  • 写入新数据到临时文件
  • 分块读取原文件内容并追加到临时文件
  • 删除原文件,将临时文件重命名为原文件名

代码示例:

#include <windows.h>
#include <stdio.h>
#include <string.h>

int main() {
    WCHAR tempPath[MAX_PATH];
    WCHAR tempFileName[MAX_PATH];
    // 获取临时目录并生成临时文件名
    if (!GetTempPath(MAX_PATH, tempPath) || !GetTempFileName(tempPath, L"APP", 0, tempFileName)) {
        printf("创建临时文件失败,错误码:%d\n", GetLastError());
        return 1;
    }

    // 打开临时文件用于写入
    HANDLE hTempFile = CreateFile(
        tempFileName,
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );

    if (hTempFile == INVALID_HANDLE_VALUE) {
        printf("打开临时文件失败,错误码:%d\n", GetLastError());
        return 1;
    }

    // 写入新数据到临时文件
    const char* newData = "这是追加到开头的大文件新内容\n";
    DWORD bytesWritten;
    if (!WriteFile(hTempFile, newData, strlen(newData), &bytesWritten, NULL)) {
        printf("写入新数据到临时文件失败,错误码:%d\n", GetLastError());
        CloseHandle(hTempFile);
        DeleteFile(tempFileName);
        return 1;
    }

    // 打开原文件读取内容
    HANDLE hOldFile = CreateFile(
        L"target.txt",
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );

    if (hOldFile != INVALID_HANDLE_VALUE) {
        char buffer[4096];
        DWORD bytesRead;
        // 分块读取原文件并写入临时文件
        while (ReadFile(hOldFile, buffer, sizeof(buffer), &bytesRead, NULL) && bytesRead > 0) {
            WriteFile(hTempFile, buffer, bytesRead, &bytesWritten, NULL);
        }
        CloseHandle(hOldFile);
    }

    CloseHandle(hTempFile);

    // 替换原文件:先删除原文件,再重命名临时文件
    if (!DeleteFile(L"target.txt")) {
        printf("删除原文件失败,错误码:%d\n", GetLastError());
        DeleteFile(tempFileName);
        return 1;
    }

    if (!MoveFile(tempFileName, L"target.txt")) {
        printf("重命名临时文件失败,错误码:%d\n", GetLastError());
        DeleteFile(tempFileName);
        return 1;
    }

    return 0;
}

关键说明

  • 不能依赖FILE_APPEND_DATA标志:该标志的核心作用是强制每次写入自动定位到文件末尾,要实现开头追加必须放弃这个标志,改用GENERIC_READ | GENERIC_WRITE权限手动控制写入位置。
  • 小文件用内存中转更高效,大文件推荐临时文件法,避免内存溢出。
  • 代码中需注意错误处理,实际使用时可根据场景补充更完善的异常判断逻辑。

内容的提问来源于stack exchange,提问作者Vinay Khatri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 23:40:34