#include <iostream> #include<fstream> using namespace std; /*本例: 1、练习ifstream、ofstream读写文件基本方法; 2、验证回车换行符号在文件读写中的状态和作用; 3、验证几种判断文件末尾的方法; 4、验证几种解决ifstream对读入类型不匹配数据的处理方法 回车与换行符: 字符 名称 ASCII值 控制字符 '/n' 换行(New line) 010 LF (Line Feed) '/r' 回车(Carriage return) 013 CR (Carriage Return) 杨小进 0:31 2009-8-12 */ //创建输入文件,为练习准备 void createFile(char *fname) { ofstream ofs(fname); ofs << "aaaaa/n"; ofs << "bbbbb/n"; ofs << "11111/n"; ofs << "22222/n"; ofs.close(); } //获取文件长度字节,会得到比输入更多的字节,因为 /n 被转换为 /r/n int getFileLen(char *fname) { ifstream ifs(fname); ifs.seekg(0, ios::end); //移动文件指针到末尾 int n = ifs.tellg(); //获取文件长度字节 ifs.seekg(ios::beg); //恢复指针到开始,对于接下来继续读有用 ifs.close(); return n; } //用read函数文本模式下读取文件,读到字节数小于真实文件大小, //因为系统读 /r/n 时又转换为 /n, 只是/n被读进来了 //若是binary模式,则会读到实际文件大小的字节 void readFileRead(char *fname, ios_base::openmode om = ios_base::in) { int n = getFileLen(fname); ifstream ifs(fname, om); char *pc = new char[n+1]; memset(pc, 0, sizeof(char)*(n+1) ); ifs.read(pc, n); if(om & ios_base::binary) { cout << " binary模式"; } cout << " read()读取了"<< ifs.gcount() << "字节:/n"; cout << pc; delete pc; ifs.close(); } //使用流提取符号读取文件,不管是何种模式,空白字符都会被 >> 略过 void readFileExtranction(char *fname) { ifstream ifs(fname, ios_base::binary); char c; cout << "binary模式 >>读取:/n"; while(!ifs.eof()) { ifs >> c; cout << c << "_"; } ifs.close(); } //使用Get在文本模式下读取文件内容,对于"/r/n"多跳过一个字符只读进'/n',指针移到'/n'后 //若在binary模式则是按照真实数据读取'/r','/n'; void readFileGet(char *fname, ios_base::openmode om = ios_base::in) { ifstream ifs(fname, om); char c; if(om & ios_base::binary) { cout << " binary模式"; } cout << " get()从第5字节开始读取3个字符:/n十进制:"; ifs.seekg(4, ios::beg); ifs.get(c); //读取第5字节,为'a' cout << int(c) << "_"; ifs.get(c); //读取下一个字节应为13 = '/r',实际读进10 = '/n' cout << int(c) << "_"; //若在binary模式下则是13 ='/r' ifs.get(c); //读取下一个字节,为'b',若是binary则是10='/n' cout << int(c) << "_"; ifs.close(); } //使用Peek读取文件内容,文本模式下对于"/r/n"读进'/n'; //在binary模式下,对于"/r/n"则会读进'/r',peek始终都不会移动文件指针 void readFilePeek(char *fname, ios_base::openmode om = ios_base::in) { ifstream ifs(fname, om); //ifstream ifs3("input.txt", ios_base::binary); char c; if(om & ios_base::binary) { cout << " binary模式"; } cout << " peek()读取第6、7、8字节:/n"; ifs.seekg(5, ios::beg); c = ifs.peek(); //读取第6字节应为13 = '/r',实际上读进10 ='/n' cout << int(c) << "_"; //若在binary模式则是13 ='/r' ifs.seekg(6, ios::beg); c = ifs.peek(); //读取第7字节,为10 ='/n' cout << int(c) << "_"; ifs.seekg(7, ios::beg); c = ifs.peek(); //读取第8字节,为'b' cout << int(c) << "_"; ifs.close(); } //通过eof()判断文件结束,若某行只有回车也算是一行,即使在文件尾部 void getOverEof(char *fname) { ifstream ifs(fname); string str; int i = 0; cout << " eof()判断文件结束"; while(!ifs.eof()) { getline(ifs, str); cout << "/n第" << ++i <<"行长度 " << str.length() << " : " << str; } ifs.close(); } //通过good()判断文件结束,同eof,若某行只有回车也算是一行,即使在文件尾部 //因为使用了binary模式,所以getline比平时多读入一个字符'/r',忽略'/n' void getOverGood(char *fname) { ifstream ifs(fname, ios_base::binary); int i = 0; string str; cout << " binary模式 good()判断文件结束"; while(ifs.good()) { getline(ifs, str); cout << "/n第" << ++i <<"行长度 " << str.length() << " : " << str; cout << " 第6字节" << int(str[5]); } ifs.close(); } //通过getline()判断文件结束,只有回车且在文件末尾的空行不算一行 void getOverGetline(char *fname) { ifstream ifs("input.txt"); int i = 0; string str; cout << " getline()判断文件结束"; while(getline(ifs, str)) { cout << "/n第" << ++i <<"行长度 " << str.length() << " : " << str; } ifs.close(); } //使用ifstream的提取符号从文本文件读入某种类型数据例如float或double时, //若遇到字符串或其它非数字符号会发生错误,造成死循环,所以需要特别处理 bool readErr(char *fname) { cout << "不匹配数据类型处理:"; ifstream ifs(fname); if( !ifs ) { cout << "/n打开文件 " << fname << " 失败/n"; return false; } int count=0; int dVal, sum=0; while( !ifs.eof() ) { ifs >> dVal; if(ifs.fail()) //错误判断,使用"!ifs"也可以,但是"ifs.bad()"不行 { ifs.clear(); //清楚错误标志 ifs.ignore(1); //忽略当前非预期字符 continue; //继续读取下一个 } else { cout << "/n第 " << ++count << "个数: " << dVal; sum += dVal; } } ifs.close(); cout << "/n总共 " << count << " 个数," << " 和为" << sum << endl; return true; } int main() { char fname[] = "input.txt"; createFile(fname); cout << "文件长度:" << getFileLen(fname) << " 字节"; cout << "/n-----------------------"; readFileRead(fname); cout << "/n-----------------------"; readFileRead(fname, ios_base::binary); cout << "/n-----------------------"; readFileExtranction(fname); cout << "/n-----------------------"; readFileGet(fname); cout << "/n-----------------------"; readFileGet(fname, ios_base::binary); cout << "/n-----------------------"; readFilePeek(fname); cout << "/n-----------------------"; readFilePeek(fname, ios_base::binary); cout << "/n-----------------------"; getOverEof(fname); cout << "/n-----------------------"; getOverGood(fname); cout << "/n-----------------------"; getOverGetline(fname); /* 总结:windows系统中使用ofstream写文本文件时系统会把'/n'转换为'/n''/r'两个字符写入文件; 若是单写入'/r'则不会做上述转换;通常读取时会相应把'/n''/r'两个字符转换为'/n'; 对于文本中单独的'/n'和'/r'读取时不会作特别转换,作为一个字符读出; 使用流输入符号">>"读取字符时,无论使用何种模式打开文件,都会忽略空白字符/n/r等; 使用get和peek读取时,若在文本模式下,对于文本中的"/r/n"只是作为一个字符'/n'对待; get和peek,若在二进制模式下,对于文本中的"/r/n"作为两个字符对待; getline在文本模式下忽略"/r/n",但是在binary模式下会忽略'/n',而不会忽略'/r'; */ cout << "/n-----------------------"; readErr(fname); cout << endl; return 0; }