C语言 有没有一种方法可以在少于3次系统调用的情况下测试文件结束?

bpzcxfmw  于 2023-02-11  发布在  其他
关注(0)|答案(2)|浏览(115)

我想测试给定文件的位置,由fd引用,是否在文件的末尾。例如,当前位置==文件大小。有没有办法在少于3个系统调用中完成此操作?这3个调用是:
1.使用lseek获取当前位置

  1. lseek到文件结尾并存储该位置(即文件大小)
    1.比较这两个值,如果它们不同,则将lseek返回到原始位置。
3pmvbmvn

3pmvbmvn1#

您只需 * 一次 * 系统调用即可测试文件结束:一个read!如果它返回0,你就在文件末尾。如果它不返回,你就不在文件末尾。
...当然,如果它返回的值大于0,那么您就不在原来的位置,因此这可能不是一个好的解决方案,但是如果您的主要任务是读取文件,那么您刚刚通过read调用读取的数据很可能就是您想要的数据。
你在一条评论中说,仅仅调用read的代码可能会"错综复杂,产生更难处理的代码",我"有点"明白你的意思。我依稀记得,在我的职业生涯中,有一两次,我希望我能知道下一个read是否会成功,在我不得不这样做之前。但那只是一两次。巨大的,绝大多数时候,至少对我来说,只读一直读直到一个读调用返回0的代码是非常自然和直接的。
增编:
K&R中的一些伪代码一直让我印象深刻,它们是grep的基本版本,在前面的一章中作为示例介绍的:

while (there's another line) {
    if (line contains pattern) {
        print it;
    }
}

这是针对基于行的输入,但更一般的模式

while (there's some input)
    process it;

具有相同的优点,并且充实到实际的read调用并不涉及太大的更改:

while (n = (read(fd, buf, bufsize)) > 0) {
    process n bytes from buf;
}

起初,嵌入的读取和测试(即对n的赋值和对0的测试,隐藏在while循环的单个控制表达式中)确实让我感到困扰,看起来似乎没有必要那么神秘,但它确实相当完美地封装了"while there's input/process it"(当有输入/处理它)的习惯用法,或者至少,给定一个C/Unix风格的读取调用,它只能在调用它的 * 之后指示EOF *。
(This与Pascal风格的I/O相反,Pascal风格的I/O在你调用它之前 * 确实 * 表示EOF,并且是,或者曾经是,导致Why is while( !feof(file) ) always wrong?成为规范SO问题的所有问题的主要动机。Brian Kernighan有一个描述,可能在 * 为什么Pascal不是我最喜欢的编程语言 * 中,实现一个Pascal风格的输入方法,在EOF发生之前显式地指出它是多么的困难和不自然。)

hc2pp10m

hc2pp10m2#

如果你有一个文件描述符,你可以使用fstat()来获得文件的大小:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

struct stat sb;

/* Upon successful completion, 0 shall be returned. 
*  Otherwise, -1 shall be returned and 
*  errno set to indicate the error
*/
if (fstat(fd, &sb) == -1) {
    perror ("fstat()");
    /* Handle error here */
}
off_t size = buf.st_size;

调用lseek()以获取当前位置。
但正如评论中指出的:

  • “无论系统调用的次数有多少,这基本上都是不可能的,因为无论测试在某个时刻告诉你位置是否在文件末尾,下一个时刻另一个进程都可能截断或扩展文件。在获得结果之后,没有任何结果是可靠的。”* - Eric Postpischil

相关问题