写入的fopen永远不会返回null

时间:2014-07-17 07:03:32

标签: c file locking stdio

我试图构建一些简单的东西来测试文件锁定。我尝试打开两个文件进行写入,两个调用都完成。打开文件后,它会显示:" hello world"。

#include <stdio.h>

int main() {
  File *fp1 = fopen("./test.txt", "w");
  fwrite("hello", 1, 5, fp1);

  File *fp2;
  if (fp2 = fopen("./test.txt", "w")) {
    fwrite("      world", 1, 11, fp2);
  }
}

在fopen的手册页中,我的印象是如果一个文件打开写入,第二个调用将返回null。我发现了一个类似的案例:Opening a file using fopen with same flag in C;在Adhip Gupta的回答之后,我试图检查&lt; = 0,但这也没有用。

我也尝试使用fcntl.h中的open()。当我预期第二次调用为-1时,打印了两个文件描述符。

#include <stdio.h>
#include <fcntl.h>

int main() {
  int id1 = open("./text.txt", O_WRONLY);
  int id2 = open("./text.txt", O_WRONLY);
  printf("%d %d\n", id1, id2);
}

为什么会这样?我在测试时没有关闭文件流/描述符;这可能是个原因吗?

2 个答案:

答案 0 :(得分:3)

这是因为当您使用"w"作为fopen的开放模式时,它会销毁文件的当前内容并以新文件开头。因此,当您第二次致电fopen时,它会成功,因为它并不关心文件是否存在,或者文件中是否有任何内容。如果路径正确并且您具有打开文件进行写入的正确权限,则fopen调用将成功。

如果你想打开一个文件只写,如果它已经存在则失败,你必须先检查文件是否存在。

答案 1 :(得分:2)

多次打开同一个文件非常有效。你提到了手册页和fcntl.h,所以我认为你正在研究一些unix变体。当应用程序打开文件进行写入时,Unix不会自动锁定文件。如果程序A和程序B打开相同的文件,它们的修改将相互覆盖;例如,当它们写入文件的不同部分时,这很有用。在您的代码中,程序A和程序B是相同的过程。

两次打开同一个文件并不是一个特例。每次调用open都会给你一个文件描述符,每个文件描述符都有自己的位置。每次调用fopen都会给你一个文件描述符和一个stdio写缓冲区。在第一个示例中,您向每个文件写入一小段数据,fwrite调用将数据存储在内存中的写缓冲区中;在调用fflush()之前,数据实际上并未写入文件。您不会明确地呼叫fflush(),也不会fclose()呼叫fflush(或达到相同的效果)。当您的程序退出时会隐式调用fclose(),但无法保证文件关闭的顺序,因此有两种可能性,您可以看到第二种:

    首先关闭
  • fp1,导致"hello"写入位置0.然后fp2关闭,导致" world"写入位置0.这会覆盖通过fp1写的5个字节。
  • 首先关闭
  • fp2,导致" world"写入位置0.然后fp2关闭,导致"hello"写入位置0.这会覆盖通过fp1写入的前5个字节,留下"hello world"

大多数unix系统仅通过lockffcntl等功能提供协作锁。如果两个程序在同一个文件上调用lockf(fd, F_LOCK, size)(不一定通过相同的文件描述符),那么第二个程序将阻塞,直到第一个程序释放其锁定。任何程序仍然可以通过调用write来修改该文件。一些unix变体(例如Linux)确实提供了强制锁定,这些锁定会影响程序是否知道锁定。