【问题标题】:Behavior when opening file in truncate mode以截断模式打开文件时的行为
【发布时间】:2023-03-07 08:55:01
【问题描述】:

我正在使用 C 文件描述符处理文件 IO。问题是我正在尝试创建一个可以容纳以下事件序列的通用类:

  1. 截断模式下的现有文本文件(即清除其当前内容)。
  2. 文本写入此文件
  3. 刚刚写入的文字被清除。
  4. 随后将新文本写入文件。

问题的简化再现代码如下:

//1.
int fd = open("/path/to_file/file.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);

//2.
const char* text = "12345";
write(fd, static_cast<const void*>(text), 5);

//3.
ftruncate(fd, 0);

//4.
const char* new_text = "678";
write(fd, static_cast<const void*>(new_text), 3);

输出是文件开头有5个\0,后面跟着字符串678,所以看起来像\0\0\0\0\0678

ftruncate 似乎认为我实际上是在尝试将文件扩展 5 个字节,如下所述:https://linux.die.net/man/2/ftruncate

如果之前的文件大于这个大小,多余的数据就会丢失。如果文件先前较短,则将其扩展,扩展部分读取为空字节 ('\0')。

但如果我使用O_APPEND 标志打开文件,那么一切正常。这个问题有什么解决办法吗?

【问题讨论】:

  • 同样来自man ftruncate:“文件偏移量没有改变。
  • 我不明白在追加模式下打开时偏移问题是如何解决的 --> 添加更多文本 --> 清除所有内容 --> 添加新文本。无需更改文件指针即可正常工作。
  • 追加模式不允许在文件内四处寻找。因此,在这种模式下,offet 似乎会自动调整以实现后一个约束。
  • 没有C/C++语言! C 和 C++ 这两种不同的语言有不同的方式来访问文件。您显然在 C++ 代码中使用了 C 方式(实际上是 POSIX 函数,而不是 C 标准)。所以这不是 C 代码。

标签: c++ file-io truncate


【解决方案1】:

这是您的代码正在执行的操作,一步一步:

//1.
int fd = open("/path/to_file/new.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);

文件被创建或截断,大小为零,打开文件描述符的当前偏移量为0。

//2.
const char* text = "12345";
write(fd, static_cast<const void*>(text), 5);

字符12345被写入文件,当前偏移量为5

//3.
ftruncate(fd, 0);

文件的长度现在为零。 当前打开文件描述符的偏移量是5。

//4.
const char* new_text = "678";
write(fd, static_cast<const void*>(new_text), 3);

字符 678 被写入文件从当前偏移量 5 开始

【讨论】:

  • 那我该如何解决呢?我尝试在调用ftruncate 后调用lseek(fd, -5, SEEK_CUR);lseek(fd, 0, SEEK_SET);,但问题仍然存在。另外,当我以附加模式打开文件,向其中写入更多文本,清除它,然后再次向其中写入文本时,为什么不会发生这种情况?按照你的逻辑,这个问题也应该会发生。
  • @Ali250: "我在拨打ftruncate 后尝试拨打 [...] lseek(fd, 0, SEEK_SET);" 你确定拨打lseek() 没有失败吗?
  • @Ali250 你没有检查 any 返回值。你需要检查每一个。
  • 我的错。我正在重试同一个损坏的 txt 文件。显然,截断标志不会清除那种文件。当我重新创建文件时,它起作用了。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-16
  • 1970-01-01
  • 2020-08-17
  • 1970-01-01
  • 2015-09-27
  • 1970-01-01
  • 2014-05-27
相关资源
最近更新 更多