回答

收藏

为什么“while (!feof (file))”总是错的?

技术问答 技术问答 406 人阅读 | 0 人回复 | 2023-09-12

使用feof()控制读取循环有什么问题?( E) i8 l5 e/ d* S7 f
    #include #include intmain(int argc,char **argv){    char *path = "stdin";    FILE *fp = argc > 1 ? fopen(path=argv[1],"r") : stdin;    if( fp == NULL()()()()()()()())()()()())()()())())()())())())())()())()))())()()))())()))())())()))()())())()()))()())()()))()()())())()()())())()))()())()))()()))()()))()())))()()()()))()()()))()()))()()()()()())()))())()))())()()()())()()()()))()())())())()())())()()())()()))()()()()))()())()()()()()()())()()))())()()()())())))()))()()())))()()()))())))()())()))()()())()()()()()()()()()())())()()())()())())))()))))())))()()()))))))())()()()()()()()()()()()()()()()()()()()()()()()()()()()()))())))))())())))))()))))))()))()))())()()()()()()()()()()()()))))()()()()()()()()()()))()()()()()()()()()()()()()()()perror(path);        return EXIT_FAILURE;   }    while( !feof(fp){ )( )( )* THIS IS WRONG *        /    * Read and process data from file… */   }    if( fclose(fp) != 0()()()()()()()())()()()())()()())())()())())())())()())()))())()()))())()))())())()))()())())()()))()())()()))()()())())()()())())()))()())()))()()))()()))()())))()()()()))()()()))()()))()()()()()())()))())()))())()()()())()()()()))()())())())()())())()()())()()))()()()()))()())()()()()()()())()()))())()()()())())))()))()()())))()()()))())))()())()))()()())()()()()()()()()()())())()()())()())())))()))))())))()()()))))))())()()()()()()()()()()()()()()()()()()()()()()()()()()()()))())))))())())))))()))))))()))()))())()()()()()()()()()()()()))))()()()()()()()()()()))()()()()()()()()()()()()()()()perror(path);        return EXIT_FAILURE;   }    return EXIT_SUCCESS;}5 D" p( A$ l; K& [# v3 N; l- A1 Y8 j
这个循环有什么问题?
$ d: y) J- F7 E, k5 S                                                                + K- O' x1 |5 X6 e
    解决方案:                                                               
+ c+ C; w0 S) I0 ?' r                                                                TL;DRwhile(!feof)这是错误的,因为它测试了一些你需要知道的无关紧要的测试你需要知道的东西。因此,你错误地执行了假设它正在访问成功读取的数据的代码,这从未发生过。
7 T4 f6 I( i  O7 ^& k我想提供一个抽象的、高层次的观点。所以,如果你对的话while(!feof)对实际操作感兴趣,请继续阅读。
( i  ^  ?# E  b, }- }并发性和同时性I/O 操作与环境互动。环境不是你程序的一部分,也不受你的控制。环境真的与你的程序同时存在。与所有并发事件一样,当前状态的问题毫无意义:并发事件之间没有同时的概念。状态的许多属性根本不同时存在存在。
6 l4 y- j4 L) ^5 U" `假设你想问,你有更多的数据吗?。您可以询问并发容器或您的 I/O 系统。但答案通常是不可操作的,所以毫无意义。那么,如果容器说是怎么办——当你试图阅读时,它可能不再有数据。同样,如果答案是否,当你试图阅读时,数据可能已经到达。结论是,有没有像我有数据这样的属性,因为你不能对任何可能的答案采取有意义的行动。(缓冲输入稍微好一点,你可能会得到一个是的,我有数据来保证,但你仍然必须能够处理相反的情况。输出必须和我描述的一样糟糕:你永远不知道磁盘或网络缓冲区是否已满。" m- T4 s/ `: x3 C6 H# x
因此,我们得出结论,询问 I/O 系统是否能够执行 I/O 操作是不可能的,其实也是不合理的。唯一可能与之互动的方法(就像并发容器一样)是尝试操作并检查它是成功还是失败。在你与环境互动的那一刻,只有在那一刻,你才能知道互动是否实际上是可能的。此时,您必须承诺果你愿意,这是一个同步点。
6 }& L0 W# A& o  d8 a  ^EOF现在我们到了EOF。EOF 是您从尝试的I/O 操作中获得的响应。这意味着你正在尝试阅读或写一些内容,但你不能读取或写任何数据,而是在输入或输出的结尾。基本上所有的 I/O API 都是这样,不管是 C 标准库、C   iostream 还是其他库。I/O 操作成功,你是根本无法知道未来的操作会成功吗?必须在响应成功或失败之前,先尝试操作。0 Q$ k3 w/ x3 P* W7 M; c2 [
例子请注意每个例子,我们首先尝试 I/O 操作,然后当结果有效时使用结果。进一步注意总是必须使用 I/O 操作结果,尽管在每个示例中使用不同的形状和形式。' w6 y9 o' z# x5 B$ Z( W+ I
C stdio,读取文件:c    for(;(;){     size_t n = fread(buf,1,bufsize,infile);        consume(buf,n);        if (n == 0) { break;        }
. j) A0 F: K' K2 ?5 T! w: i我们必须使用的结果是n,读取的元素数量(可能少于零)。- a: d8 g9 M0 }$ ~. x" b
C标准输入法,scanf:c    for (int a,b,c; scanf("%d %d %d",&a,&b,&c) == 3. ) {       consume(a,b,c);    }" w) L4 Y: X  I( S9 g1 l! B' `- O
结果是 的返回值scanf,即转换元素数。/ p$ ?( s0 c6 Y$ t
C  、iostreams 格式化提取:c    for (int n; std::cin >> n; ) {        consume(n);    }8 d/ O: m; r* U2 E0 H
我们必须使用的结果是std::cin它本身可以在布尔的上下文中进行评估,并告诉我们流动是否仍然存在good()状态。
0 J/ ?% q3 a$ W) K, T6 S7 e9 ZC   ,iostreams getline:c    for (std::string line; std::getline(std::cin,line); ()()()()()consume(line);    }
) ~4 w) M2 n2 N5 b+ A2 _$ Q: O0 j我们必须再次使用它std::cin,就像以前一样。
. J  l& e/ v8 h$ H' e: u* q+ EPOSIX,write(2)刷新缓冲区:c    char const * p = buf;    ssize_t n = bufsize;    for (ssize_t k = bufsize; (k = write(fd,p,n)) > 0; p  = k,n -= k) {}    if (n != 0* error,failed to write complete buffer */ }
; t  E8 y* |$ ?( h我们在这里使用的结果是k,字节数。这里的重点是,我们只能知道写入操作后写了多少字节。- G# `! C9 e& Z
POSIX getline()c    char *buffer = NULL;    size_t bufsiz = 0;    ssize_t nbytes;    while ((nbytes = getline(&buffer,&bufsiz,fp)) != -1)              * Use nbytes of data in buffer *      free(buffer);
+ K  g' i% @, C我们必须使用的结果是nbytes,直到包含换行符的字节数(如果文件没有以换行符结束,则为 EOF)。
. g/ j2 D3 |( S* T请注意,-发生错误或到达 EOF 函数显式返回(而不是 EOF!)。" \) |- Y: K" H9 `; h* G
你可能会注意到,我们很少拼出实际的单词EOF。我们通常以其他我们更感兴趣的方式检测错误的条件(例如,我们不能尽可能多地执行我们想要的 I/O)。每个示例中都有一些 API 功能可以明确地告诉我们遇到了 EOF 状态,但这不是一个非常有用的信息。它比我们经常关心的细节要多得多。I/O 是否成功,而不是如何失败。/ a% M8 m% W, P+ [. l
实际查询 EOF 状态的最后一个例子:假设你有一个字符串,并且想测试它是否代表一个整数,除了空间,没有额外的位置。C   iostreams,这样:```c
- F+ g  A5 U: s                std::string input = ”   123   “;   // example
( ?3 G( S! ~$ Q4 ~std::istringstream iss(input);int value;if (iss >> value >> std::ws && iss.get() == EOF)    consume(value);} else    // error,"input" is not parsable as an integer}```0 D3 W, Q% ?$ y
我们在这里使用两个结果。iss检查流对象本身是否以格式提取value成功。然而,在消耗空间后,我们实施了另一个 I/O/ 操作,iss.get()并期待它作为 EOF 失败,如果整个字符串被格式化提取消耗,就会发生这种情况。
5 I) v  T# l5 W0 a7 k在 C 标准库中,您可以strto*l检查指针是否已到达输入字符串的末尾,以实现与函数相似的功能。
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则