Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 是否有一种快速可靠的POSIX方法来检查当前文件偏移量是否在文件末尾?_C_Linux_Posix - Fatal编程技术网

C 是否有一种快速可靠的POSIX方法来检查当前文件偏移量是否在文件末尾?

C 是否有一种快速可靠的POSIX方法来检查当前文件偏移量是否在文件末尾?,c,linux,posix,C,Linux,Posix,如何使用低级POSIX函数检查当前写入位置是否在文件末尾?第一个想法是使用lseek和fstat: off_t sk; struct stat st; sk = lseek (f, 0, SEEK_CUR); fstat (f, &st); return st->st_size == sk; 但是,st->st_size是否反映实际大小而不是磁盘文件大小,即不包括内核缓冲数据 另一个想法是使用 off_t scur, send; scur = lseek (f, 0, SEEK_

如何使用低级POSIX函数检查当前写入位置是否在文件末尾?第一个想法是使用lseek和fstat:

off_t sk;
struct stat st;
sk = lseek (f, 0, SEEK_CUR);
fstat (f, &st);
return st->st_size == sk;
但是,
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;
但这似乎不是一种快速且适当的方法

此外,这两种方式似乎都是非原子的,因此,如果有另一个进程附加到文件中,则可以在检查当前偏移量后更改大小

但是,
st->st_size
是否反映实际大小而不是磁盘文件大小,即不包括内核缓冲数据

我不明白你说的内核缓冲数据是什么意思。
st->st_size
中的数字反映了文件的大小(以字符为单位)。因此,如果文件有
1000000
个字符,那么
st->st_size
的数字将是
1000000
,字符位置从
0
999999

在POSIX系统中,有两种获取文件大小的方法:

  • 执行
    off\u t saved=lseek(fd,0,SEEK\u END)
    ,返回实际位置(必须保存,以便稍后恢复),以及第二次调用
    off\t file\u size=lseek(fd,saved,SEEK\u SET)
    返回到以前的位置,但以数字形式返回以前的位置(这是文件的最后一个位置,在最后一个字符之后)。如果选中此项,则它将与
    st->st\u size
    返回的值匹配
  • 对文件描述符执行
    stat(2)
    ,以获得您提到的值
如果有多个线程或进程与您共享文件描述符(通过
dup(2)
系统调用,或
fork()
ed进程),如果它们在两个
lseek
调用之间执行
read(2)
write(2)
调用,则第一种方法有一些缺点,您将丢失以前在文件上的位置,并且无法恢复到正确的位置。这很奇怪,因此第一种方法不值得推荐

最后,内核中的文件缓冲与文件大小没有关系。您总是在
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);
}

st_size
是当时文件的大小,使用内核缓冲池中的最新数据,或者当前未使用的磁盘上的最新数据。当您从检查返回时,结果是无用的。如果要确保自动附加到文件,请按设计使用
O_append
模式;它不进行I/O,只是更改文件在内存控制块中的位置。你是对的,两个大纲解决方案都有TOCTOU(检查时间,使用时间)问题,因为它们是非原子的。我认为没有原子调用来完成这项工作——文件描述符的位置和文件的大小是不相关的操作。一个主要的问题是“你为什么需要知道这个”?如果使用
O_APPEND
,则所有写入都将在末尾。如果您使用
pwrite()
,它将在您指定的位置写入。出于好奇,根据写入位置是否在末尾,您会做什么、不做什么或做什么不同的事情?这可能会影响我们的回答。@JonathanLeffler我不认为有原子能来完成这项工作。POSIX能够自动附加到文件,同时也能够写入任何位置的方法是在附加模式下打开文件,并使用
pwrite()
写入所需的偏移量。不幸的是,在Linux上,无论传递给
pwrite()
的偏移量是多少,
pwrite()
都将以
O_append
模式追加到文件中。您将以
1000013
字节文件结束,但只使用一到两块磁盘空间。仅当基础文件系统支持时。并非所有文件系统都支持.UNIX,因为它的起源几乎都支持它。我的BSD系统告诉我大约4Mb的磁盘使用量(st_blocksz*st_blocks),但我知道它确实支持它。我们的想法是要知道,至少,
st_size
是一个好的、可靠的了解方法。@AndrewHenle,at&t unix v7支持稀疏文件,所以恐怕几乎所有Unice都支持。当然,在非本机文件系统(如iso cdrom映像或稀有文件系统)中并非如此
$ 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
$ _