我试图构建一些简单的东西来测试文件锁定。我尝试打开两个文件进行写入,两个调用都完成。打开文件后,它会显示:" 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);
}
为什么会这样?我在测试时没有关闭文件流/描述符;这可能是个原因吗?
答案 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系统仅通过lockf
和fcntl
等功能提供协作锁。如果两个程序在同一个文件上调用lockf(fd, F_LOCK, size)
(不一定通过相同的文件描述符),那么第二个程序将阻塞,直到第一个程序释放其锁定。任何程序仍然可以通过调用write
来修改该文件。一些unix变体(例如Linux)确实提供了强制锁定,这些锁定会影响程序是否知道锁定。