int ReadDataFromFiles( string strPath, vector<double> &vData )
{
ifstream sourceFiles( strPath );
if ( !sourceFiles.is_open() )
{
cout<<"Open Files Failed!"<<endl;
sourceFiles.close();
return -1;
}
// 获取文件长度
sourceFiles.seekg(0, ios::end);
int datasNum = sourceFiles.tellg();
sourceFiles.seekg(0, 0);
vData.resize( datasNum, 0.0 );
int dataIndex = 0;
while( !sourceFiles.eof() )
{
sourceFiles >> vData[ dataIndex ];
dataIndex++;
}
sourceFiles.close();
return 0;
}
最近要使用ifstream的getline函数来获取文件的每一行数据,但就搞不懂怎样才能确保获取数据时所使用的缓冲区大小足够大。在刚开始的时候,我是采用了以下的手段:
代码
#include <iostream>
#include <fstream>
using namespace std;
#define BASE_BUFF_MAX_LEN 10
int main()
{
char *filePath = "E:\\test.txt";
int bufLen = BASE_BUFF_MAX_LEN;
char *buf = new char[bufLen];
ifstream fin;
fin.open(filePath,ios::in);
fin.getline(buf,bufLen);
while(fin.fail())
{
fin.getline(buf,bufLen);
}
cout<<buf<<endl;
}
当缓冲区不够大的时候,getline函数也会对缓冲区输入数据,但同时也会把ifstream的状态位failbit设置了,于是fail函数会返回true。于是上述代码会嵌入死循环,由于处于fail状态下的ifstream,其getline函数不会再读入任何数据,因此后续的getline调用没有效果,并且fail函数一直返回true。
看看文档,原来可以使用ifstream的clear函数重置状态位,于是以下方法就能达到目的:
代码
#include <iostream>
#include <fstream>
using namespace std;
#define BASE_BUFF_MAX_LEN 10
int main()
{
char *filePath = "E:\\test.txt";
int bufLen = BASE_BUFF_MAX_LEN;
char *buf = new char[bufLen];
ifstream fin;
fin.open(filePath,ios::in);
fin.getline(buf,bufLen);
while(fin.fail())
{
fin.clear(ios::goodbit);
fin.getline(buf,bufLen);
}
cout<<buf<<endl;
}
同时,ifstream的gcount函数会返回上一次读取操作中,读入的有效字符数,但就不保存缓冲区中最后的'\0',因此如果缓冲区大小为10,gcount将输出9。上述方法其实也比较别扭,更好的方法是使用<string>头文件定义的getline:
代码
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
#define BASE_BUFF_MAX_LEN 10
int main()
{
char *filePath = "E:\\test.txt";
ifstream fin;
fin.open(filePath,ios::in);
string s;
getline(fin,s);
cout<<s<<endl;
}
简单直接。
假设有一个叫 data.txt 的文件, 它包含以下内容:
Fry: One Jillion dollars.
[Everyone gasps.]
Auctioneer: Sir, that's not a number.
数据读取, 测试 。
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//输出空行
void OutPutAnEmptyLine()
{
cout<<"n";
}
//读取方式: 逐词读取, 词之间用空格区分
//read data from the file, Word By Word
//when used in this manner, we'll get space-delimited bits of text from the file
//but all of the whitespace that separated words (including newlines) was lost.
void ReadDataFromFileWBW()
{
ifstream fin("data.txt");
string s;
while( fin >> s )
{
cout << "Read from file: " << s << endl;
}
}
//读取方式: 逐行读取, 将行读入字符数组, 行之间用回车换行区分
//If we were interested in preserving whitespace,
//we could read the file in Line-By-Line using the I/O getline() function.
void ReadDataFromFileLBLIntoCharArray()
{
ifstream fin("data.txt");
const int LINE_LENGTH = 100;
char str[LINE_LENGTH];
while( fin.getline(str,LINE_LENGTH) )
{
cout << "Read from file: " << str << endl;
}
}
//读取方式: 逐行读取, 将行读入字符串, 行之间用回车换行区分
//If you want to avoid reading into character arrays,
//you can use the C++ string getline() function to read lines into strings
void ReadDataFromFileLBLIntoString()
{
ifstream fin("data.txt");
string s;
while( getline(fin,s) )
{
cout << "Read from file: " << s << endl;
}
}
//带错误检测的读取方式
//Simply evaluating an I/O object in a boolean context will return false
//if any errors have occurred
void ReadDataWithErrChecking()
{
string filename = "dataFUNNY.txt";
ifstream fin( filename.c_str());
if( !fin )
{
cout << "Error opening " << filename << " for input" << endl;
exit(-1);
}
}
int main()
{
ReadDataFromFileWBW(); //逐词读入字符串
OutPutAnEmptyLine(); //输出空行
ReadDataFromFileLBLIntoCharArray(); //逐词读入字符数组
OutPutAnEmptyLine(); //输出空行
ReadDataFromFileLBLIntoString(); //逐词读入字符串
OutPutAnEmptyLine(); //输出空行
ReadDataWithErrChecking(); //带检测的读取
return 0;
}
输出结果为:
Read from file: Fry:
Read from file: One
Read from file: Jillion
Read from file: dollars.
Read from file: [Everyone
Read from file: gasps.]
Read from file: Auctioneer:
Read from file: Sir,
Read from file: that's
Read from file: not
Read from file: a
Read from file: number.
Read from file: 数据读取,
Read from file: 测试
Read from file: 。
Read from file: Fry: One Jillion dollars.
Read from file: [Everyone gasps.]
Read from file: Auctioneer: Sir, that's not a number.
Read from file: 数据读取, 测试 。
Read from file: Fry: One Jillion dollars.
Read from file: [Everyone gasps.]
Read from file: Auctioneer: Sir, that's not a number.
Read from file: 数据读取, 测试 。
Error opening dataFUNNY.txt for input
Press any key to continue
运用ifstream的getline时需要注意的问题
我们在应用中经常会遇到从文件中读行的操作,
当然方法有多种,这里我想和大家探讨一下用ifstream的getline方法:
主要code如下:
……
const int MAXLEN = 256;
std::vector<std::string> vecFilelines;
std::ifstream fs("test.txt");
if (fs.good())
{
char stringline[MAXLEN];
while (!fs.eof())
{
fs.getline(stringline, MAXLEN);
vecFilelines.push_back(stringline);
}
}
……
初步看一下上面的代码没什么问题,
如果你所要读的每一行的长度不超过255,程序运行也不会有问题
但当你所要读的长度超过了255,就有问题了,我尝试的现象是:
当读到第一个超过255的行时,程序会陷入死循环,内存会被慢慢耗尽。
经过对istream里getline方法的分析,找出原因如下:
……
_Myt& __CLR_OR_THIS_CALL getline(_Elem *_Str,
streamsize _Count, _Elem _Delim)
{ // get up to _Count characters into NTCS, discard _Delim
_DEBUG_POINTER(_Str);
ios_base::iostate _State = ios_base::goodbit;
_Chcount = 0;
const sentry _Ok(*this, true);
if (_Ok && 0 < _Count)
{ // state okay, use facet to extract
int_type _Metadelim = _Traits::to_int_type(_Delim);
_TRY_IO_BEGIN
int_type _Meta = _Myios::rdbuf()->sgetc();
for (; ; _Meta = _Myios::rdbuf()->snextc())
if (_Traits::eq_int_type(_Traits::eof(), _Meta))
{ // end of file, quit
_State |= ios_base::eofbit;
break;
}
else if (_Meta == _Metadelim)
{ // got a delimiter, discard it and quit
++_Chcount;
_Myios::rdbuf()->sbumpc();
break;
}
else if (--_Count <= 0)
{ // buffer full, quit
_State |= ios_base::failbit;
break;
}
else
{ // got a character, add it to string
++_Chcount;
*_Str++ = _Traits::to_char_type(_Meta);
}
_CATCH_IO_END
}
*_Str = _Elem(); // add terminating null character
_Myios::setstate(_Chcount == 0 ? _State | ios_base::failbit : _State);
return (*this);
}
……
当你读到一个大于255的行时,由逻辑
else if (--_Count <= 0)
{ // buffer full, quit
_State |= ios_base::failbit;
break;
}
会将文件的_State置为ios_base::failbit,从而_Ok变成false
而后再继续getline时,_Ok将会一直为false,而getline会一直返回空串,在while中陷入死循环。
改善如下:
……
const int MAXLEN = 256;
std::vector<std::string> vecFilelines;
std::ifstream fs("test.txt");
if (fs.good())
{
char stringline[MAXLEN];
while (!fs.eof())
{
if (fs.getline(stringline, MAXLEN).good())
{
vecFilelines.push_back(stringline);
}
else
{
// add you logic to deal with the unexpected situation
break;
}
}
}
……