C语言 读取/备份文本文件



我有以下代码尝试读取文本文件,进行备份,并将读取文件字符串传递给进一步的处理例程。我看到的行为非常出乎意料。

01: rewind(PPLFile);
02: fseek(PPLFile, 0, SEEK_END);
03: unsigned long fsize = ftell(PPLFile);
04: char *string = (char*)calloc(fsize + 1, sizeof(char));
05: rewind(PPLFile);
06: fread(string, sizeof(char), fsize, PPLFile);
07: FILE* PPLBackup;
08: char* fileSuffix = ".backup";
09: char* PPLBackupLocation = (char*)calloc(strlen(basePath) + strlen(fileSuffix) + 1, sizeof(char));
10: strcpy(PPLBackupLocation, basePath);
11: strcat(PPLBackupLocation, fileSuffix);
12: PPLBackup = fopen(PPLBackupLocation, "w");
13: fprintf(PPLBackup, fileContent);
14: fclose(PPLBackup);
15: free(PPLBackupLocation);

文件句柄*PPLFile以前已使用 w+a+ 标志打开,具体取决于最初写入文件的先前代码中的某些情况。

我认为的概念很简单:

  1. 将指针移到文件末尾并感知其位置以建立文件大小(以字节为单位(
  2. 创建字节大小加 1 的空字符串(对于空终止符(
  3. 将整个文件内容倒带并读取到字符串中,直至检测到的文件大小
  4. 创建备份文件名和文件指针
  5. 将从原始文件读取的整个字符串写入新的备份文件。
  6. 关闭备份文件并继续处理读取字符串

有两个令人不安的症状:

  1. 包含原始文件的 *char 字符串有更多的零(文本文件中的数千个 ~=20MB(,因此最后一个非零值可能是从末尾开始的 3000 个字节。似乎比原始文件小。
  2. 写入备份文件时,生成的文件比原始文件一点,末尾附加了一个看似随机的原始文件的额外样本,又是几千字节。

很简单,到底是怎么回事?

这一行不好:

13: fprintf(PPLBackup, fileContent);

如果文件包含像%s这样的字符序列,那么fprintf将在堆栈上查找其他数据。

您应该改用fwrite

13: fwrite(fileContent, fsize, 1, PPLBackup);

或者至少这样做:

13: fprintf(PPLBackup, "%s", fileContent);

为什么你用fread((阅读而用fprintf((而不是fwrite((写作?以及您使用 fprintf(( 的方式,您将受到文件中第一个%登录(格式字符串漏洞(的摆布。

此外,请确保两个文件以相同的模式(文本模式与二进制模式(打开。通常,fread((/fwrite(( 倾向于与二进制模式一起使用。

这个完整的程序在 Linux 上对我有用。 它有克拉斯的改动。 注意我必须使用 fsize 作为全局,因为传递要复制的文件的 char * 内容会中断,如果以后被 strlend - 出于显而易见的原因

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
unsigned long fsize=0L;
char *get_file(FILE *PPLFile) {
    rewind(PPLFile);
    fseek(PPLFile, 0, SEEK_END);
    fsize = ftell(PPLFile);
    char *string = (char*)calloc(fsize + 1, sizeof(char));
    rewind(PPLFile);
    fread(string, sizeof(char), fsize, PPLFile);
    return string;
}
void write_file(char *basePath, char *fileContent) {
 FILE* PPLBackup;
 char* fileSuffix = ".backup";
 char* PPLBackupLocation = (char*)calloc(strlen(basePath) + strlen(fileSuffix) + 1, sizeof(char));
 strcpy(PPLBackupLocation, basePath);
 strcat(PPLBackupLocation, fileSuffix);
 PPLBackup = fopen(PPLBackupLocation, "w");
 fwrite(fileContent, fsize, 1, PPLBackup);
 fclose(PPLBackup);
 free(PPLBackupLocation);
}

多个问题

  1. 正如@Klas Lindbäck&@Medinoc所提到的,不要使用fprintf()fwrite()好多了。

  2. @Klas Lindbäck所说,请确保以二进制模式打开文件读取和写入fopen(PPLBackupLocation, "wb")

  3. 应评估fread()的返回值,如果良好,则用于fwrite()

  4. calloc(fsize + 1, sizeof(char))不需要添加 1。

最新更新