说道文件操作,可能很多人都或多或少知道一些,但是你是否曾遇到一些莫名其妙的问题呢,你是否了解如何真正正确的判断是否读到文件末尾呢(!f.eof()----to young, to simple),你是否真正了解seekp()/seekg()/tellg()/tellp()呢?如果这些你都明白了,那么这篇文章你就不需要看了。但是如果你还不太明白,我们就一起探讨一下:
经过多番查找资料以及验证,发现:
文件读取时当刚好读取到文件最后一条记录时,文件的读指针会+1,即使+1到达了文件末尾,读函数或者操作符都不负责检查是否到达文件末尾。这就会导致当文件指针越界时iso_base::eofbit仍然没有置位依然是0,当再次进入循环读取记录时,发现无记录可读,读取失败,此时置位eofbit,(事实上此时failbit也会置位)。再次判断循环条件才会出错。所以循环会多执行一次。
那么为什么会多读出一个B呢,是不是指针回退了呢,事实并非如此,标准库不可能这么傻。看下面这段程序:
这就是因为读取World!时当读到‘!’字符时文件读指针已达到文件末尾,但读取字符串工作并未完成,因为没有遇到结束符。继续尝试读取,结果读到文件尾部(读取错误,置eofbit,failbit为1)。返回已经读取的字符串(这是重载">>"做的事情);
继续看下一个例子:
这是为什么呢?为什么World!会输出两次呢?
原因很简单,当读完World!是并未到达文件末尾,继续尝试读取下一个字符串。然而前面的空白(字符串出现之前)会被忽略,结果读到文件末尾,尝试读取文件末尾出错。且读到0个字节。那么str不变。输出上一次结果。
所有上面这些错误都会置eofbit,failbit,以及读取返回非真。
所以最保险,最安全的代码形式应该是:
这个也许会让我们有点小疑惑,ios_base::end不是文件末尾吗,是的,没错,但是我们需要说明的是文件指针到达文件结束并不置eofbit为1.只有尝试读取文件结束位置才置位eofbit为1(同时置位failbit为1);
1.文件读写指针到达文件末尾并不会引起ios_base::eofbit置位为1.自然f.eof()也不回返回true.只有当试图读取文件尾(结束位置)时才置ios_base::eofbit为1,同时置文件读写指针位置为-1;所以当我们判断是否读到文件末尾时,还应当判断读写是否出错。
2.以字节流读写文件时,需将数据视为char,char*,string类型,其他类型的读写必须经过必要的转换,否则会出现错误。
3.其他读写函数以此类推。
在C++文件操作中,有四个函数是让我们自己来自由控制读写位置的,他们分别是:seekp()/seekg()/tellg()/tellp().
函数原型:
seekp:设置输出文件流的文件流指针位置
seekg:设置输入文件流的文件流指针位置
函数原型:
ostream& seekp( streampos pos );
ostream& seekp( streamoff off, ios::seek_dir dir );
istream& seekg( streampos pos );
istream& seekg( streamoff off, ios::seek_dir dir );
函数参数
pos:新的文件流指针位置值
off:需要偏移的值
dir:搜索的起始位置
dir参数用于对文件流指针的定位操作上,代表搜索的起始位置
在ios中定义的枚举类型:
enum seek_dir {beg, cur, end};
每个枚举常量的含义:
ios::beg:文件流的起始位置
ios::cur:文件流的当前位置
ios::end:文件流的结束位置
seekp():设置写指针位置。
seekg():设置读指针位置。
它们对于fstream对象来说,seekp()/seekg()等价,因为读写指针是同一个指针,而且tellg()/tellp()也等价,因为读写指针在同一个位置。而对于ifstream/ofstream就需要使用特定函数。
还有一点需要注意,seekp()/seekg()的越界问题,当函数的偏移量参数超出文件大小(如文件只有10字节大小,seekg(20))
1.首先,写在文件大小允许的情况下是没有越界这么一说的:
C++中负责的输入/输出的系统包括了关于每一个输入/输出操作的结果的记录信息。这些当前的状态信息被包含在io_state类型的对象中。io_state是一个枚举类型(就像open_mode一样),以下便是它包含的值。
ios_base::goodbit 无错误
ios_base::eofbit 已到达文件尾
ios_base::failbit 非致命的输入/输出错误,可挽回
ios_base::badbit 致命的输入/输出错误,无法挽回
这四个标记位均为bit位,标记值为0或者1,每个标记位0表示清除,1表示设置。
他们分别对应四个函数:
good():返回goodbit的值。
eof():返回eofbit的值.
fail():返回failbit的值。
bad():返回badbit的值。