用ifstream的eof(),竟然读到文件最后了,判断eof还为false。网上查找资料后,终于解决这个问题。

参照文件:http://tuhao.blogbus.com/logs/21306687.html

在使用C/C++读文件的时候,一定都使用过eof()这个函数来判断文件是否为空或者是否读到文件结尾了,也会在使用这个函数的过程中遇到一些问题,如不能准确的判断是否为空或者是否到了文件尾,以至于有些人可能还会怀疑这个函数是不是本身在设计上就有问题。

先来看看如下这段代码:

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
  char ch = 'x';
  ifstream fin("test.txt" /*, ios::binary*/);
  if (fin.eof())
  {
    cout << "file is empty."<<endl;
    return 0;
  }

while (!fin.eof())
  {
    fin.get(ch);
    cout << ch;
  }    
  system("pause");
  return 0;
}

编译并运行以上代码,

如果test.txt不存在,程序会形成死循环,fin.eof()永远返回false,
如果test.txt为空,程序打印出一个x字符,
当test.txt中存在一字符串“abcd”且没有换行时,程序打印出“abcdd”,
当存在以上字符串并且有一新的空行时,程序打印出“abcd”加上一空行。

这种现象可能让很多人很迷惑,程序运行的结果似乎很不稳定,时对时错。使用binary模式读时结果一样。在这里,大家可能有一个误区,认为eof()返回true时是读到文件的最后一个字符,其实不然,eof()返回true时是读到文件结束符0xFF,而文件结束符是最后一个字符的下一个字符。如下图所示:

因此,当读到最后一个字符时,程序会多读一次(编译器会让指针停留在最后一个字符那里,然后重复读取一次,这也就是就上面最后一个字符会输出两次的原因。至于是不是所有的编译器都这样处理我就不太清楚了,我使用的VC6,VC8似乎都是这样的)

问题出来了,就要找出对应的解决之道,要解决以上的问题,只需要调整一下条件语句即可:
                          fin.peek() == EOF   或   fin.get(ch)                                 

再来看一下另外一种情况:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
    string str;
    ifstream fin("test.txt"/*, ios::binary*/);
    if (fin.peek() == EOF)
    {
        cout << "file is empty."<<endl;
        return 0;
    }

while (!fin.eof())
    {
        fin >> str;
        cout << str;
    }   
    system("pause");
    return 0;
}

上述代码在VC8下编译运行,发现,当文件结尾没有空行时,结果正确,当结尾有空行时,最后一个字符串将被重复输出一次, 而VC6的情况则有所不同,没有重复输出,但输出了一个空行。

因此,为了保证在不同的编译器下得到一致的我们期望的结果,将条件语句做一下修改:
                                           fin >> str                                                      

综上所述,我们可以得到以下结论:
1. 判断文件是否为空时使用peek函数,若peek返回EOF则文件为空;
2. 读取文件过程中,读取非char型时,使用peek判断文件尾将不再适用,循环判断条件应改用>>操作符进行读取,若读入char型缓冲区,peek函数会表现得很好。

peek() —— 此函数将返回输入流文件的下一个字符,但它不移动内置指针。

c++ 读取文件 最后一行读取了两次的更多相关文章

  1. 有关fgetc配合feof逐行读取文件最后一行读取两遍的错觉?

    最近在做一个wifiap设置的接口,用户首先获取到当前wifi 热点的ssid 和pwd,然后修改,保存. 获取信息的时候是fopen对应的hostapd.conf文件,逐行读取,查找匹配的参数. 修 ...

  2. PureBasic 读取文件中一行的两个数据例子

    , "Test1.txt") ; if the file could be read, we continue... , "Test2.txt") ) = ; ...

  3. shell读取文件每一行的方式

    1.使用read命令读取一行数据 while read myline do echo "LINE:"$myline done < datafile.txt 2.使用read命 ...

  4. shell脚本中每次读取文件的一行

    写法一: #!/bin/bash while read linedo      echo $line     #这里可根据实际用途变化 done < file          #需要读取的文件 ...

  5. python读取文件,python读取的1变成\ufeff1

    '\ufeff1' movies={} fm=open(self.path+'/movie.txt',encoding='utf-8') w2=open('./data/1.txt','a') for ...

  6. python读取文件首行和最后一行

    python读取文件最后一行两种方式 1)常规方法:从前往后依次读取 步骤:open打开文件. 读取文件,把文件所有行读入内存. 遍历所有行,提取指定行的数据. 优点:简单,方便 缺点:当文件大了以后 ...

  7. Perl读取标准输入<STDIN>、读取文件输入<>和chomp函数

    读取标准输入<STDIN> <STDIN>表示从标准输入中读取内容,如果没有,则等待输入.<STDIN>读取到的结果中,如果没有意外,都会自带换行符. 例如,tes ...

  8. 类似于c语言读取文件进行解析

    $log_file_name = 'D:/static/develop/kuai_zhi/acagrid.com/public/Logs/'.date('Ym').'/'.date('d').'_er ...

  9. java 读取文件流

    搬运自速学堂:https://www.sxt.cn/Java_jQuery_in_action/ten-iqtechnology.html JAVA中IO流体系: 四大IO抽象类 ·InputStre ...

  10. C++/Php/Python/Shell 程序按行读取文件或者控制台

    写程序经常需要用到从文件或者标准输入中按行读取信息,这里汇总一下.方便使用 1. C++ 读取文件 #include<stdio.h> #include<string.h> i ...

随机推荐

  1. Object Detection(RCNN, SPPNet, Fast RCNN, Faster RCNN, YOLO v1)

    RCNN -> SPPNet -> Fast-RCNN -> Faster-RCNN -> FPN YOLO v1-v3 Reference RCNN: Rich featur ...

  2. js混杂笔记

    1.判断对象为空的方法 1)Object.keys({}).length === 0 // true 2)Object.getOwnPropertyNames({}).length === 0 // ...

  3. [Xcode 实际操作]七、文件与数据-(3)创建文本文件、属性列表文件、图片文件

    目录:[Swift]Xcode实际操作 本文将演示如何创建各种类型的文件. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit class V ...

  4. 深入V8引擎-Time模块介绍

    积跬步,行千里,先从最简单的开始写. 这一篇介绍V8中的时间模块,与libuv粗糙的update_loop_time方法不同,V8有一套独立完整的类负责管理时间. 该类位于src/base/platf ...

  5. W3C标准以及规范

    1.什么是DOCTYPE DOCTYPE是document type(文档类型)的简写,用来说明你用的XHTML或者HTML是什么版本.其中的DTD(例如xhtml1-transitional.dtd ...

  6. mysql5.7日志时间戳(log_timestmaps)与系统时间不一致问题以及日志报Got an error reading communication packets情况分析

    一.mysql安装后error_log日志时间戳默认为UTC(如下图),因此会造成与系统时间不一致,与北京时间相差8个小时. 解决errro_logs时间戳与linux系统时间不一致问题 step1: ...

  7. Opencv级联分类器实现人脸识别

    在本章中,我们将学习如何使用OpenCV使用系统相机捕获帧.org.opencv.videoio包的VideoCapture类包含使用相机捕获视频的类和方法.让我们一步一步学习如何捕捉帧 - 第1步: ...

  8. [Leetcode] 002. Add Two Numbers

    https://leetcode.com/problems/add-two-numbers/ public class Solution { public ListNode addTwoNumbers ...

  9. 单台服务器最大tcp连接

    如果对服务器进行压力测试,常常出现这种情况 tcp连接数过多 netstat   -an    windows查看tcp连接数 那么怎么增加单台服务器的最大连接数呢?       最简单的办法,增加内 ...

  10. h5点击区域和实际区域对不上

    点击区域和实际区域对不上 然后点击后触发的其实是上面的区域,会导致事件触发错误