如何使用低级 POSIX 函数检查当前写入位置是否位于文件末尾?第一个想法是使用 lseek 和 fstat:
off_t sk;
struct stat st;
sk = lseek (f, 0, SEEK_CUR);
fstat (f, &st);
return st->st_size == sk;
Run Code Online (Sandbox Code Playgroud)
但是,是否st->st_size反映了实际大小而不是磁盘文件大小,即不包括内核缓冲数据?
另一个想法是使用
off_t scur, send;
scur = lseek (f, 0, SEEK_CUR);
send = lseek (f, 0, SEEK_END);
lseek (f, scur, SEEK_START);
return scur == send;
Run Code Online (Sandbox Code Playgroud)
但这似乎不是快速且充分的方法。
此外,这两种方式似乎都是非原子的,因此如果有另一个进程附加到文件,则可以在检查当前偏移量后更改大小。
Lui*_*ado -1
但是,是否
st->st_size反映了实际大小而不是磁盘文件大小,即不包括内核缓冲数据?
我不明白你所说的内核缓冲数据是什么意思。中的数字st->st_size反映了文件的大小(以字符为单位)。因此,如果文件有1000000字符,则数字st->st_size将为1000000,字符位置从0到999999。
POSIX系统中有两种获取文件大小的方法:
off_t saved = lseek(fd, 0, SEEK_END);,它返回实际位置(您必须保存它,以便稍后恢复它),第二次调用off_t file_size = lseek(fd, saved, SEEK_SET);返回您之前的位置,但以数字形式返回您之前的位置(这是文件,在最后一个字符之后)如果您选中此项,这将与 . 返回的值匹配st->st_size。stat(2)对文件描述符执行 a以获取您提到的值。如果您有多个线程或进程与您共享文件描述符(通过dup(2)系统调用或ed 进程),第一种方法有一些缺点,如果它们在您的两个调用之间fork()执行read(2)、write(2)或调用,您将丢失您之前在文件上的位置,并且将无法恢复到正确的位置。这很奇怪,并且使得第一种方法不值得推荐。lseek(2)lseek
最后,内核中完成的文件缓冲与文件大小没有关系。您始终可以在 上获得真实的文件大小stat(2)。唯一会让您感到困惑的是,当您运行以下代码片段时,在内核中完成的节省(但这对您来说是透明的,您不必考虑它,除非您要将文件复制到另一个文件地方)。只需运行这个小程序:
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd = open("file", O_WRONLY | O_CREAT | O_TRUNC, 0666);
lseek(fd, 1000000, SEEK_SET);
char string[] = "Hello, world";
write(fd, string, sizeof string);
close(fd);
}
Run Code Online (Sandbox Code Playgroud)
其中将以1000013字节文件结束,但仅使用一两个磁盘空间块。这是一个有洞的文件,其中1000000您写入的字符串之前有零字节,并且系统不会在磁盘中为其分配块。只有当您在这些块上写入时,系统才会用新块填充您写入的部分以保存您的数据......但在此之前,系统将向您显示零字节,但它们不会存储在任何地方。
$ ll file
-rw-r----- 1 lcu lcu 1000013 4 jul. 11:52 file
$ hd file
[file]:
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :................
*
000f4240: 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 00 :Hello, world.
000f424d
$ _
Run Code Online (Sandbox Code Playgroud)