c - 当同时指定 O_APPEND 和 O_TRUNC 时,它不会截断吗?
c - When specify O_APPEND and O_TRUNC together, it won't truncate?
如题,当同时指定O_APPEND
和O_TRUNC
时,打开文件时不优先运行
所以,当指定O_APPEND
时,我如何仍然运行先分类文件?
@更新:
O_APPEND
和 O_TRUNC
可以完美地协同工作,这是我之前代码中的错误。
关于原子
以下代码证明 O_APPEND
将确保每个 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_TRUNC
和 O_APPEND
(至少在 Linux 上),文件将被截断:
// test.cc
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main() {
open("test.txt", O_RDWR | O_TRUNC | O_APPEND);
}
这是显示文件被截断的示例:
$ echo 'abc' > test.txt
$ g++ test.cc
$ ./a.out
$ cat test.txt
# no output here
O_APPEND
不保证原子写入。如果您使用 open/close/read/write 而不是 stdio,则无法保证线程安全。如果您在 Linux,我怀疑写入您请求的字节数是原子的,但是,没有规范要求这样做。如果 write()
returns 小于请求的大小,则无法保证下一次写入(缓冲区的其余部分)中的数据一定会在第一次部分写入之后继续。
如果您希望多线程应用程序按照您请求的顺序生成输出(如果所有内容都写入文件),我强烈建议您阅读互斥锁或其他锁定机制。
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
注意它是怎么说的 "Any combination of the following may be used" 并且该列表包括 O_APPEND
和 O_TRUNC
.
我真的不知道 O_TRUNC
会如何与 O_APPEND
交互,因为第一个只是告诉操作系统在打开文件时如何处理文件,而 O_APPEND
告诉操作系统在调用 write
和 writev
函数时要做什么。
此外,为了消除其他答案给您带来的困惑。 O_APPEND
does guarantee atomicity of the write: "If the O_APPEND flag of the file status flags is set, the file offset shall be set to the end of the file prior to each write and no intervening file modification operation shall occur between changing the file offset and the write operation."
为了消除进一步的混淆,我在 POSIX、this part of the standard is relevant.
下关于文件操作原子性的评论中看到
如题,当同时指定O_APPEND
和O_TRUNC
时,打开文件时不优先运行
所以,当指定O_APPEND
时,我如何仍然运行先分类文件?
@更新:
O_APPEND
和 O_TRUNC
可以完美地协同工作,这是我之前代码中的错误。
关于原子
以下代码证明 O_APPEND
将确保每个 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_TRUNC
和 O_APPEND
(至少在 Linux 上),文件将被截断:
// test.cc
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main() {
open("test.txt", O_RDWR | O_TRUNC | O_APPEND);
}
这是显示文件被截断的示例:
$ echo 'abc' > test.txt
$ g++ test.cc
$ ./a.out
$ cat test.txt
# no output here
O_APPEND
不保证原子写入。如果您使用 open/close/read/write 而不是 stdio,则无法保证线程安全。如果您在 Linux,我怀疑写入您请求的字节数是原子的,但是,没有规范要求这样做。如果 write()
returns 小于请求的大小,则无法保证下一次写入(缓冲区的其余部分)中的数据一定会在第一次部分写入之后继续。
如果您希望多线程应用程序按照您请求的顺序生成输出(如果所有内容都写入文件),我强烈建议您阅读互斥锁或其他锁定机制。
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
注意它是怎么说的 "Any combination of the following may be used" 并且该列表包括 O_APPEND
和 O_TRUNC
.
我真的不知道 O_TRUNC
会如何与 O_APPEND
交互,因为第一个只是告诉操作系统在打开文件时如何处理文件,而 O_APPEND
告诉操作系统在调用 write
和 writev
函数时要做什么。
此外,为了消除其他答案给您带来的困惑。 O_APPEND
does guarantee atomicity of the write: "If the O_APPEND flag of the file status flags is set, the file offset shall be set to the end of the file prior to each write and no intervening file modification operation shall occur between changing the file offset and the write operation."
为了消除进一步的混淆,我在 POSIX、this part of the standard is relevant.
下关于文件操作原子性的评论中看到