2

所以我有一个大文件,一旦达到一定大小,我想完全删除前半部分并将后半部分向下移动,有效地将其缩小一半。这是我的想法:

FILE *fp, *start;
int ch, block_length, filesize;
char c;

//open the file and initialize pointers
fp = fopen(FILEPATH, "rb+");
start = fp;
rewind(start);

//Check the size of the file
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);    

if(filesize >= LOG_MAX_FILE_SIZE)
{
  //Go to middle of file
  fseek(fp, (-1) * LOG_MAX_FILE_SIZE/2, SEEK_END);

  //Go forwards until you get a new line character to avoid cutting a line in half
  for(;;)
  {
     //Read char
     fread(&ch, 1, 1, fp);

     //Advance pointer
     fseek(fp, 1, SEEK_CUR);

     if( (char)ch == '\n' || ch == EOF)
        break;
  }

  //fp is now after newline char roughly in middle of file

  //Loop over bytes and put them at start of file until EOF
  for(;;)
  {
     //Read char
     fread(&ch, 1, 1, fp);

     //Advance pointer
     fseek(fp, 1, SEEK_CUR);

     if(ch != EOF)
     {
        c = (char)ch;
        fwrite(&c,1,1,start);
        fflush(start);

        //Advance start
        fseek(start, 1, SEEK_CUR);
     }

     else
        break;
  }

  //Calculate length of this new file
  block_length = ftell(start);

  //Go back to start
  rewind(start);

  //Truncate file to block length
  ftruncate(fileno(start), block_length);

}

但是,这似乎在做一些非常非常奇怪的事情(用'f'填充文件,混合行和其中的一些字符等)。有没有人知道我在这段代码中可能做错了什么?预先感谢!

4

2 回答 2

1

我认为部分问题是您fseek在阅读时使用。对 fread 和 fwrite 的调用使文件指针前进。如果您调用 fseek,它将跳过下一个字符。

在下面的代码序列中,fread调用将读取一个字符并将当前偏移量推进到下一个字符。随后的fseek然后跳过该字符并移动到下一个。所以它会读取每个第二个字符。

fread(&ch, 1, 1, fp);
fseek(fp, 1, SEEK_CUR);

write 调用也存在同样的问题(它不需要后续的查找)。此外,由于对 OP 的编辑显示 start 和 fp 是相同的值,因此逻辑将不正确(您需要单独的文件指针才能使用该逻辑)。

于 2013-02-15T23:45:59.737 回答
0

找到开始位置后,您可以大块复制文件(例如一次 64 KB),从尾部读取,然后跳向开始并写入,然后再跳回尾部......

ftruncate()是释放空间的最后一步。

考虑让读取文件流和写入文件流指向同一个文件是否更容易。减少对单个流的搜索(代码更简单)。这是我可能会做的。

于 2013-02-15T23:49:09.933 回答