`

c++ ifstream 读文件 最后一行读两次

 
阅读更多

http://blog.csdn.net/rebel_321/article/details/4927464

 

用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++输入文件流ifstream用法详解_ims的博客-CSDN博客1

    - `getline`:读取一行文本。 - `ignore`:忽略指定数量的字符或遇到特定字符。 - `peek`:查看但不读取下一个字符。 - `read`:读取指定数量的字节。 - `putback`:将一个字符放回流中。 - `unget`:撤销最近一次的...

    文件读写操作总结(自己找的有用的)

    本文将围绕这两个语言中的文件操作进行详细阐述,包括C的基础文件操作、C++的文件操作、WinAPI接口的文件操作以及C++ Builder库中的文件操作,并特别讨论特殊文件的处理。 首先,我们来看基于C的文件操作。C语言的...

    实现STL文件的读取保存

    接下来是读取ASCII STL文件的实现,`ReadASCII`函数是主要的读取函数,它使用`ifstream`打开并读取文件,通过循环逐行读取面片信息,将顶点信息保存到`_mapPointList`这个`map`中,使得相同的顶点只被记录一次。...

    C++文件读写总结 !!!

    对于字符串读取,可以使用 `getline()` 函数来一次性读取一行: ```cpp char sentence[101]; fin.getline(sentence, 100); ``` ##### 4. 关闭文件 完成读取后,记得关闭文件以释放资源: ```cpp fin.close(); ``...

    文件显示复制算法文档及C/C++源码

    C++标准库提供了fstream库来处理这些操作,如`ifstream`用于读取文件,`ofstream`用于写入文件。 复制文件的过程则更为复杂,它不仅包括读取源文件,还需要将数据写入目标文件。常见的文件复制算法有逐块复制和缓冲...

    C++_fstream的使用方法

    使用`getline`和`ifstream`读取文件 `getline`函数非常适用于读取含有空白符(如空格、换行符等)的文本数据。 - **示例**: 假设有一个名为`data.txt`的文件,内容如下: ``` Fry: One Jillion dollars. ...

    C++简繁体转换 代码 + DEMO

    3. 读取文件内容到字符串或字符缓冲区。 4. 根据需要进行GB2312到GBK或GBK到GB2312的转换。 5. 创建`ofstream`对象以覆盖原文件内容或写入新文件。 6. 将转换后的内容写入文件并关闭流。 在实际操作中,还需要考虑...

    C++程序计算一门课的成绩

    描述中提到,数据文件每一行包含一个学生的名字以及十次测验的分数,程序会计算这些分数的平均值并将结果写入新的输出文件。 在提供的代码片段中,我们看到了C++的标准库被用来处理文件输入输出(I/O)。`#include...

    cpu_linux.rar_cpu_linux.cpp_linux 读取文件_proc cpu

    2. 读取内容:使用`fgets()`或`std::ifstream`读取文件内容,每次读一行。 3. 解析数据:对读取到的每一行进行处理,找出以"cpu"开头的行。可以使用字符串查找函数如`strstr()`或正则表达式库如`boost::regex`进行...

    VC读写txt文件[整理].pdf

    3. **问题解答:为什么最后一行会被显示两次?** - 这个问题发生在读取文件的循环中。当读取文件的最后一行时,`i_file &gt;&gt; out_text;`会读取一行,然后`good()`依然返回`true`,导致下一次循环再次执行`i_file &gt;&gt; ...

    c语言读取csv文件和c++读取csv文件示例分享

    在C++中,我们可以利用`std::ifstream`来读取文件,`std::getline()`获取每一行,并结合`std::istringstream`进一步分割字符串。`Trim()`函数用于去除字符串前后的空白字符。下面是C++的示例: ```cpp #include #...

    qt c++ 实现高效率的统计字数

    通过打开文件、逐行读取内容,然后将每一行的字符数累加,我们可以计算出文件的总字数。在Qt中,可以使用`QFile`和`QTextStream`类来实现这一功能,它们提供了一种更方便且安全的文件操作方式。 2. **统计字数**:...

    代码行统计

    2. **逐行读取**:读取文件内容时,程序需要一次读取一行,这可以通过`getline()`函数完成。每读取一行,就进入下一步处理。 3. **行处理**:对每一行进行分析,判断是否为空行或注释。C/C++的注释有两种形式:单行...

    VC平台ASCII格式STL文件的读取与线显示

    2. 遍历文件:逐行读取文件内容,根据上述结构解析每个面片的信息。 3. 解析信息:对每行数据进行处理,提取顶点坐标和法向量。注意,由于STL文件的特性,顶点坐标可能需要进行浮点数转换。 4. 存储数据:将解析出的...

    读取stardict字典

    在C++中读取Stardict字典,我们首先要打开这两个关键文件。使用标准库中的`ifstream`类可以处理这一任务,但需要注意的是,`.dict.dz`文件实际上是Gzip压缩的,所以我们需要先解压,这可能需要用到第三方库如libz或...

    Data测试3 读取_csv数据读取比较_csv_

    CSV文件由一行行的数据组成,每行数据通过逗号分隔,每一列代表一个特定的属性或值。例如,一个简单的CSV文件可能包含姓名、年龄和城市等字段: ``` John,25,New York Jane,30,Los Angeles ``` 在C++中,我们可以...

    从文件读入选项.rar

    `read()`一次性读取整个文件,`readline()`读取一行,`readlines()`读取所有行并返回列表。 - `with`语句可以确保文件在使用完毕后自动关闭,防止资源泄漏。 2. **Java**: - `java.io.File` 类代表文件对象,`...

    pgm数据读取与保存

    - `ifstream`用于读取,`ofstream`用于写入,两者都需要用`open()`函数指定文件名,并通过`close()`关闭文件。 6. **错误处理**: - 必须检查文件是否成功打开,并处理可能的读取或写入错误。 - 对于无效的PGM...

    Jump-too-much-of-a-line.rar_Too Much

    在C++编程中,有时我们需要处理文本文件时,可能需要忽略文件的开头部分,比如第一行,然后从第二行开始读取数据。标题"Jump-too-much-of-a-line.rar_Too Much"暗示了这个场景,描述中也明确指出我们要跳过文件的第...

    vc++文件传输例子.rar

    `std::getline`函数用于从输入文件中读取一行,然后将其写入输出文件。 然而,文件传输可能涉及更复杂的情况,如网络传输。在这种情况下,我们通常会使用套接字(socket)编程。在Windows环境中,这可以通过Winsock...

Global site tag (gtag.js) - Google Analytics