C - 读取然后写入文件而不使用内存(就地)?

时间:2017-04-22 00:04:33

标签: c string file system-calls

我需要移动'左边是一个大字符串X空格。它太大了,不适合记忆,所以我需要做到这一点。 我需要使用最少量的系统调用来完成它。

我知道我可以使用缓冲区并重用内存来最小化内存消耗,然后使用fseek - >阅读 - >写下直到我完成,但我有兴趣看看是否可以做到这样的事情。

1 个答案:

答案 0 :(得分:1)

您可以通过一次移动一个字节来完成此操作,如下所示。但是,如果允许更大的缓冲区(一次移动4096个字节),您将获得更好的性能。我们显然使用了一些堆栈内存,但它不会根据前缀的大小或文件的大小进行分配,因此我们可以将其称为“就地”。

void inPlaceTruncate(
    char const * const filename,
    int shift)
{
  FILE * f;
  if ((f = fopen(filename, "r+")) == NULL) {
    // handle error
  }

  // go to the end
  if (fseek(f, 0, SEEK_END) != 0) {
    // handle error
  }

  // get current file size
  long int const oldFileLen = ftell(f);
  if (oldFileLen < 0) {
    // handle error
  } else if (oldFileLen < shift) {
    // make the file empty
    shift = oldFileLen;
  }

  // go back to the beginning
  if (fseek(f, 0, SEEK_SET) != 0) {
    // handle error
  }

  // move file
  char buffer;
  for (long int pos = 0; pos < oldFileLen-shift; ++pos) {
    // slow to be repeatedly fseeking...
    if (fseek(f, pos+shift, SEEK_SET) != 0) {
      // handle error
    }

    if (fread(&buffer, sizeof(buffer), 1, f) != 1) {
      // handle error
    }

    if (fseek(f, pos, SEEK_SET) != 0) {
      // handle error
    }

    if (fwrite(&buffer, sizeof(buffer), 1, f) != 1) {
      // handle error
    }
  }

  // shrink file -- in a rather unpleasent way
  #ifdef WIN32
  if (_chsize(fileno(f), oldFileLen-shift) != 0) {
    // handle error
  }
  #else
  // we're assuming if its not windows, it's at least posix compliant.
  if (ftruncate(fileno(f), oldFileLen-shift) != 0) {
    // handle error
  }
  #endif

  fclose(f);
}

文件收缩的相关post

编辑实际回答OP的问题。

编辑以记录错误处理的位置。

另外,正如评论中所指出的,这只会处理小于2GB的文件和移位。为了处理更大的文件并解决fseek() / ftell() / ftruncate() 32位限制(在Windows上,您可以使用_chsize_s),您需要确定使用相对偏移量在循环中进行文件大小化,并对ftruncate()进行多次调用。