【问题标题】:How to truncate a file in C?如何在C中截断文件?
【发布时间】:2010-10-26 18:50:23
【问题描述】:

我正在使用 C 将一些数据写入文件。我想删除文件中以前写入的文本,以防它比我现在写的要长。 我想减小文件的大小或截断到最后。我该怎么做?

【问题讨论】:

    标签: c file


    【解决方案1】:

    如果您想将文件的先前内容保留到一定长度(长度大于零,其他答案提供),那么 POSIX 为该作业提供了 truncate()ftruncate() 函数。

    #include <unistd.h>
    int ftruncate(int fildes, off_t length);
    int truncate(const char *path, off_t length);
    

    该名称表示主要用途 - 缩短文件。但是如果指定的长度比之前的长度长,文件会增长(零填充)到新的大小。注意ftruncate() 作用于文件描述符,而不是FILE *;你可以使用:

    if (ftruncate(fileno(fp), new_length) != 0) ...error handling...
    

    但是,您应该知道,混合文件流 (FILE *) 和文件描述符 (int) 访问单个文件很容易导致混淆 - 请参阅 cmets 了解一些问题。这应该是最后的手段。

    不过,出于您的目的,打开时截断可能就是您所需要的,为此,其他人提供的选项就足够了。


    对于 Windows,有一个函数 SetEndOfFile() 和一个相关函数 SetFileValidData() 可以做类似的工作,但使用不同的界面。基本上,您会寻找要设置文件结尾的位置,然后调用该函数。

    还有一个函数_chsize(),如sofranswer 中所述。

    【讨论】:

    • 非常相似,兰斯!至少我们中的一个人可能得到了正确的信息。 (在最近的 POSIX 标准中,使用 是不必要的;不过,为了安全,它并没有什么害处。)
    • 在 c++ vs 2003 中有这样的功能我找不到吗?不包括帮助也许我错过了什么?我不想用 w 打开文件,而是使用已经打开的文件
    • 我不确定。大多数 POSIX 函数在 MSVC 中都可用,但 Microsoft 决定需要在函数名称的开头放置一个下划线——因此是 _truncate() 和 _ftruncate()。此外,这些是 C 函数,而不是 C++;您可能需要以这种方式追踪它。在我拥有的 MSVC 2008 中,我没有找到 unistd.h 标头;我不确定这在其他版本中是否可用,或者我是否只是没有找到正确的地方。
    • 我很确定(至少在 Mac 上)在打开的文件上调用 ftruncate(file no(fp)) 是不安全的。 fp 的内部读写缓冲区都不会被刷新。在刷新写入缓冲区之前调用std::fflush,之后调用std::freopen 重新初始化fp
    • @Sebastian:C 中没有 std::fflushstd::freopen;你一定是把它和另一种语言混淆了——大概是 C++。这取决于您所说的“不安全”是什么意思。当然,您会立即跳出文件流的知识,在其背后进行操作。没有什么会刷新缓冲区;在使用ftruncate(fileno(fp)) 之前,您应该使用fflush(fp)。接下来会发生什么取决于您打开文件的方式、是否在下一次操作之前重新定位文件流以及其他详细信息。但是,在 o/s 级别,该文件将被截断。
    【解决方案2】:

    在 Windows 系统中,没有标题 &lt;unistd.h&gt;,但您可以使用

    截断文件
     _chsize( fileno(f), size);
    

    【讨论】:

    • _chsize_s 为 64 位:_chsize_s(_fileno(f), size);
    • _fileno 函数如果我们使用 FILE 结构真的很有帮助
    • 那不是 MS-Windows 独有的功能吗?!
    • fileno() 好像是deprecated,现在最好用_fileno()
    • @AlexisWilke 他确实说过“在 Windows 系统中”;所以是的,_chsize() 是一个仅限 Windows 的函数。
    【解决方案3】:

    这是您的操作系统的功能。标准的 POSIX 方法是:

    open("file", O_TRUNC | O_WRONLY);
    

    【讨论】:

    • 这会将文件截断为 0 字节大小。
    • 问题显然是将文件截断/缩小到特定大小。
    • 我同意这不是问题的答案,而是标题的答案。我来到这里试图将其截断为 0 字节,并且标题与我在 google 上的搜索相匹配,所以我认为这是有效的 +1 投票,因为提到了一个标准。
    • 记得#include #include #include
    【解决方案4】:

    如果要在某种 UNIX 风格下运行,这些 API 应该可用:

       #include <unistd.h>
       #include <sys/types.h>
    
       int truncate(const char *path, off_t length);
       int ftruncate(int fd, off_t length);
    

    根据我的 Linux 机器上的“man truncate”,这些都符合 POSIX。请注意,如果您传递的长度大于当前长度,这些调用实际上会增加文件的大小 (!)。

    【讨论】:

      【解决方案5】:

      如果您想截断整个文件,打开文件进行写入即可。否则,您必须打开文件进行读取,并将文件中您要保留的部分读取到临时变量中,然后将其输出到您需要的任何地方。

      截断整个文件:

      FILE *file = fopen("filename.txt", "w"); //automatically clears the entire file for you.
      

      截断部分文件:

      FILE *inFile("filename.txt", "r");
      //read in the data you want to keep
      fclose(inFile);
      FILE *outFile("filename.txt", "w");
      //output back the data you want to keep into the file, or what you want to output.
      

      【讨论】:

      • 这是一种非常低效的执行方式。 @Jonathan Leffler 的方法更可取,如果您的平台不允许,至少执行一次写入/重命名循环,以防止在发生崩溃时丢失数据(将数据复制到临时名称下的新文件,然后交换名称(如果可能的话,原子地),然后删除旧文件)
      • 加上如果文件不存在 fclose 有未定义的行为
      【解决方案6】:

      啊,你编辑了你的帖子,你用的是C。当你打开文件时,像这样用“w+”模式打开它,它会截断它准备写:

      FILE* f = fopen("C:\\gabehabe.txt", "w+");
      fclose(file);
      

      要在 C++ 中截断文件,您可以简单地为文件创建一个 ofstream 对象,使用 ios_base::trunc 作为文件模式来截断它,如下所示:

      ofstream x("C:\\gabehabe.txt", ios_base::trunc);
      

      【讨论】:

      • fopen 将截断文件“gabehabe.txt”的内容并将文件指针定位到开头,对吗?但是它会在重新定位文件指针之前清空文件的内容吗?
      猜你喜欢
      • 2011-09-26
      • 2011-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-14
      • 2012-09-08
      • 1970-01-01
      相关资源
      最近更新 更多