作为标题,同时指定O_APPEND
和O_TRUNC
时,打开时不会首先截断文件。
因此,当指定O_APPEND
时,如何仍然首先截断文件?
@更新:O_APPEND
和O_TRUNC
可以完美地协同工作,这是我先前代码中的错误。
关于原子
以下代码证明O_APPEND
通过将offset设置为在原子系统调用内自动结束,从而确保每个write()
中的追加操作都是原子的。
// atomic append
// TLPI exercise 5.3
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int atomic_append(int argc, char *argv[]) {
char *buf = "a";
int opt;
if(argc < 3) {
printf("command format: %s\n", "atomic_append <filename> <byte-count> [x]");
return -1;
}
char *fp = argv[1];
int bc = atoi(argv[2]);
int flag_append = 1;
if(argc >=4 && strcmp(argv[3], "x")==0) {
flag_append = 0;
}
int fd = open(fp, O_RDWR | O_CREAT | O_TRUNC | (flag_append?O_APPEND:0), 0644);
int i=0;
while(i++ < bc) {
if(!flag_append) {
lseek(fd, 0, SEEK_END);
}
write(fd, buf, 1);
}
close(fd);
return 0;
}
int main(int argc, char *argv[]) {
atomic_append(argc, argv);
return 0;
}
编译和运行的步骤:
编译为
a.out
./a.out a1 100000 & ./a.out a1 100000
./a.out a2 100000 x & ./a.out a2 100000 x
ll -h a*
然后您可以看到a1和a2的大小不同。
这是TLPI练习5.3中的练习。
最佳答案
O_APPEND
和O_TRUNC
可以正常工作。如果没有,我会怀疑您的操作系统中存在错误(或更可能是您的代码中存在错误)。
这是一个简单的测试程序,可以在MacOS,OpenBSD和两个不同版本的Linux上正常运行:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#define FN "truncateme"
int
main(int argc, char **argv)
{
char buf[16];
ssize_t r;
int fd;
if ((fd = open(FN, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1)
err(1, "open 1 ");
if (write(fd, "foo", 3) != 3)
err(1, "write 1");
close(fd);
if ((fd = open(FN, O_RDWR|O_TRUNC|O_APPEND, 0600)) == -1)
err(1, "open 2");
if (write(fd, "1", 1) != 1)
err(1, "write 2");
close(fd);
if ((fd = open(FN, O_RDONLY)) == -1)
err(1, "open 3");
if ((r = read(fd, buf, 16)) != 1)
errx(1, "read %d != 1", (int)r);
return 0;
}
Here is the POSIX description of
open
注意它说的是“可以使用以下任何组合”,并且该列表同时包含O_APPEND
和O_TRUNC
。我真的不知道
O_TRUNC
如何与O_APPEND
交互,因为第一个只是在打开时告诉操作系统该文件的处理方式,而O_APPEND
则告诉操作系统该做什么。调用write
和writev
函数时要执行的操作。另外,为消除混乱,其他答案也给了您。
O_APPEND
does guarantee atomicity of the write:“如果设置了文件状态标志的O_APPEND标志,则应在每次写操作之前将文件偏移设置为文件的末尾,并且在更改文件偏移和写操作之间不得进行任何中间文件修改操作”。为了消除进一步的混乱,我在关于POSIX下文件操作的原子性的评论中看到了this part of the standard is relevant.