【问题标题】:Truncate or resize a file in order to modify its end截断或调整文件大小以修改其结尾
【发布时间】:2013-03-01 09:18:51
【问题描述】:

我有一个FILE* file,其中包含一些二进制数据。假设这个数据是一个双精度列表,最后一个条目是一个描述双精度的字符串。我想修改这个字符串(新字符串可能更短)。所以首先我删除旧字符串。我需要找到字符串的起点:

fseek(file,-size(sring.size()),SEEK_END);

然后我该怎么办?我找到了Delete End of File 链接,但我不知道该使用哪一个... 重新调整文件大小后,我可以简单地使用fwrite 编写我的新字符串吗?

【问题讨论】:

    标签: c++ file binary resize


    【解决方案1】:

    FILE* 和 iostream 都不支持截断。如果你想 编辑一个文件,使新文件比旧文件短,你 有两个解决方案:

    • 通常的解决方案是将原始文件复制到新的 文件,随时进行任何更改。完成后关闭 新文件,验证没有错误(很重要的一点), 然后删除原始文件并重命名为新文件以具有 原名。这可能会在 Unix 系统上引起问题,如果 有指向原始文件的硬链接。 (通常,这 不是问题,因为现在每个人都使用软链接。如果是, 你应该 stat 原来的,如果 st_nlink 字段是 大于1,将新文件复制到原文件上,然后 删除新文件。)另一方面,它是最通用的 选项;它适用于所有类型的修改,在任何地方 文件。

    • 通常在较低级别有系统特定的功能 截断文件。在 Unix 下,这是ftruncate。但 您需要找到要截断的字节数 第一的; ftruncate 需要一个打开的文件,但它不会截断 在文件中的当前位置。所以你必须1)找到 文件中最后一行的开头,2)寻找它,3)写 新值,4)调用ftell(或ftello,如果长度可以 太大而无法放入 long) 以找到新的结束位置。 此时,您遇到了同步问题 FILE*与下级;就个人而言,我会fclose 文件, 然后用open重新打开它,然后在文件上执行ftruncate 从此打开的描述符。 (事实上​​,就个人而言,我会做 整个工作使用openreadlseekwriteftruncateclose。也许stat 找出文件长度 正面。如果你不需要翻译双打, FILE* 确实没有添加任何内容。

    作为一般规则,我会采用第一个解决方案,并且只尝试 第二个如果结果太慢。 (如果文件 包含数十亿个双精度数,例如,复制它们 需要一些时间。)

    【讨论】:

    • 很好的答案,但它为您提出的第二个解决方案提出了一些问题。你的意思是我需要先 fopen,然后找到我要截断的位置,然后 fclose,打开为什么?为什么我不能打开文件?以及“如果您不必翻译双打,则 FILE* 确实没有添加任何内容”是什么意思。
    • 是否与您给@aaaaaa123456789 的评论有关?
    • @user2110463 第二个问题:<stdio.h>(和 iostream)真正添加到您的基本系统级 IO 的是 1)可移植性 2)解析各种类型的输入(doubleint , 等等。)。如果你不需要后者,而你使用的是ftruncate,所以你没有前者,你还不如在基本的系统级IO方面做所有事情。
    • @user2110463 关于第一个问题,它可能只是过于谨慎,但标准并没有真正指定<stdio.h> 如何与系统级 IO 一起工作。我希望fseek-fputs-ftruncate-fclose 能够工作,但我之前一直很惊讶,我不知道有什么保证。
    • @user2110463 是的,这与我对@aaaaaa123456789 的回复中的问题完全相同。我认为只是在fflush 和关闭 should 之间滑动ftruncate 工作,但我已经看到了很多我认为应该工作但没有工作的东西,在没有明确的保证……
    【解决方案2】:

    如果您想调整文件大小,那么ftruncate() (http://www.linuxmanpages.com/man2/ftruncate.2.php) 就是您要寻找的功能。不过,您需要在FILE * 结构上调用fileno() 来获取ftruncate() 的文件描述符。

    至于在文件减小后追加新数据(新字符串),只要寻找到最后(fseek(file, 0, SEEK_END))和fwrite()'ing 就应该这样做。

    编辑:记得在截断文件之前调用fflush()

    【讨论】:

    • 非常感谢!但我真的需要在 ftruncate() 之后寻求结局吗?它应该已经在正确的位置了!?
    • 没有问题是愚蠢的,如果它真的来自缺乏知识。每个人都曾经一无所知。至于为什么(如果其他人想知道,或者如果你不清楚),这是因为文件指针仍然指向它指向的任何地方——不一定指向文件的新结尾。即使是这样,无论如何,fseek() 也是一个很好的编程习惯,以防万一。
    • @aaaaaa123456789 好的做法是相对的。同时使用低级函数(如ftruncate)和FILE* 操作进行操作充满危险,并且从一开始就是不好的做法。 fflush() 应该会有所帮助,但我不会在ftrunctate 之后尝试对文件进行任何操作(并希望fclose() 除了close() 不会做任何事情,因为之前的fflush())。
    • @JamesKanze 您可以关闭文件,用truncate() 截断它,然后重新打开它。这对我来说似乎是一个不必要的负担,因为该文件应该在fflush() 之后没有缓冲数据。但是,如果您想格外小心,那就是要走的路。另一种方法是fflush() 文件(确保没有待处理的写入)并使用truncate() 完全忽略文件已打开。这应该是有效的(如果fflush() 做到了它所说的那样,它应该),虽然我不知道这些库和类似的东西有多兼容。
    • @aaaaaa123456789 对于<stdio.h> 的任何合理实现,只需在调用ftruncate() 之前进行刷新就足够了。但在过去的30年里,我看到了很多不合理的事情,所以我变得非常谨慎。 (恕我直言,除非他想解析双打,否则使用低级例程完成整个事情不会更费力,而且会更可靠。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    • 1970-01-01
    • 2015-05-19
    • 1970-01-01
    相关资源
    最近更新 更多