2

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

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+ora+标志打开,具体取决于最初编写文件的先前代码中的某些情况。

我认为的概念很简单:

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

有两个令人不安的症状:

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

很简单,到底发生了什么?

4

4 回答 4

2

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

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

于 2013-09-25T08:54:29.563 回答
2

这一行不好:

13: fprintf(PPLBackup, fileContent);

如果文件包含类似%sthen的字符序列,fprintf则会在堆栈上查找其他数据。

您应该fwrite改用:

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

或者至少这样做:

13: fprintf(PPLBackup, "%s", fileContent);
于 2013-09-25T08:54:45.623 回答
0

这个完整的程序适用于我在 Linux 上。它有克拉斯的改动。请注意,我必须将 fsize 用作全局,因为传递要复制的文件的 char * 内容会破坏,如果它后来被strlen'd - 原因很明显

#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);
}
于 2013-09-25T13:39:23.600 回答
0

多个问题

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

  2. @Klas Lindbäck 说,确保二进制模式打开文件读写。如fopen(PPLBackupLocation, "wb").

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

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

于 2013-09-25T13:41:03.900 回答