我需要移动'左边是一个大字符串X空格。它太大了,不适合记忆,所以我需要做到这一点。 我需要使用最少量的系统调用来完成它。
我知道我可以使用缓冲区并重用内存来最小化内存消耗,然后使用fseek
- >阅读 - >写下直到我完成,但我有兴趣看看是否可以做到这样的事情。
答案 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()
进行多次调用。