流 流的概念 流就是流动,从某一处流向另一处的过程 在C++中,流的基本单位是字节,因此也称为字节流
流的四种状态
goodbit 有效状态 badbit 系统级别的错误,不可恢复 failbit 可恢复的错误 eofbit 到达了流的末尾
标准IO
标准IO四种状态和重置忽略函数的使用 io标准库,与IO常用函数
#include <iostream> using std::cin;using std::cout;using std::endl;using std::istream;
标准IO使用
#include <iostream> using std::istream;using std::cin;using std::cout;using std::endl;using std::string;void printStreamStatus (istream& is) { cout << "is goodbit:" << is.good () << endl; cout << "is badbit:" << is.bad () << endl; cout << "is failbit" << is.fail () << endl; cout << "is eofbit" << is.eof () << endl; } void test0 () { int number = -1 ; printStreamStatus (cin); cin>>number; cout << "number:" << number << endl; printStreamStatus (cin); string line; cin >> line; cout << "line:" << line << endl; printStreamStatus (cin); } int main () { test0 (); return 0 ; }
以上代码,当输入正确格式(先输入int类型,再输入string类型),则输出结果
is goodbit:1 is badbit:0 is failbit0is eofbit0123 number :123 is goodbit:1 is badbit:0 is failbit0is eofbit0abc line :abc is goodbit:1 is badbit:0 is failbit0is eofbit0
可以看到除goodbit以外其余皆为假,则流的状态是正常的 但当格式输入有误时,比如输入了string
is goodbit:1 is badbit:0 is failbit0is eofbit0abc number :0 is goodbit:0 is badbit:0 is failbit1is eofbit0line :is goodbit:0 is badbit:0 is failbit1is eofbit0
number的值因为输入有误成了0(如果是输入了比int还大的数字,会打印越界后的数字而不是0),goodbit也成了假,输入stirng的时刻直接没有执行,goodbit也为假,但我们发现failbit为真,所以在第一次输入有误时我们可以弥补错误
void test0 () { int number = -1 ; printStreamStatus (cin); cin >> number; cout << "number:" << number << endl; printStreamStatus (cin); cin.clear (); cin.ignore (1024 ,'\n' ); string line; cin >> line; cout << "line:" << line << endl; printStreamStatus (cin); }
此时我们发现无论第一次输入是否有误,都不会影响输入string的过程
假设我们在对cin重置后没有清空缓冲区,那么输入的数据会保留到下一次输入,也同样会取消string的输入,第一次输入的数据就是line的值
输出结果
is goodbit:1 is badbit:0 is failbit0is eofbit0abc number :0 is goodbit:0 is badbit:0 is failbit1is eofbit0abc line :abc is goodbit:1 is badbit:0 is failbit0is eofbit0
自定义安全输入
既然已经掌握了四种状态表示和如何重置流与清空缓冲区 那么可以试着写一个专门用于输入的函数
#include <iostream> using std::istream;using std::cin;using std::cout;using std::endl;using std::string;int readIntergerNumber () { int number = -1 ; cout<<">:Please Input an interger number" <<endl; while (cin>>number && !cin.eof ()) { if (cin.bad ()) { cout<<">:cin stream has broken" <<endl; return -1 ; } else if (cin.fail ()) { cout<<">:Please reInput a vaild interger number" <<endl; cin.clear (); cin.ignore (1024 ,'\n' ); } else { cout<<">:Number:" <<number<<endl; return number; } } } void test1 () { readIntergerNumber (); } int main () { test1 (); return 0 ; }
缓冲区 注:当前代码在Linux系统中执行,其他编译器可能情况有所不同
三种缓冲区
全缓冲区:只有缓冲区满时才会输出/刷新 行缓冲区:只有缓冲区满/遇到换行时才会输出/刷新 非缓冲区:不带缓冲区,有多少数据就输出/刷新多少数据,类似于word编辑
#include <iostream> using std::istream;using std::cin;using std::cout; using std::endl;using std::string;int main () { cout<<"Hello<<endl;//可以认为endl就是换行符,也就表明cout使用的就是行缓冲区 for(int i = 0;i < 512;++i) { cout<<'a'; } Sleep(3000);//睡眠三秒 }
此时我们发现,当Hello打印后,过了三秒之后512个a才被打印出来 而当i循环改为1025时,可以发现打印完a之后才进行休眠 可知cout的默认缓冲区大小为1024字节
文件IO 三种输出函数
cout打印缓冲区内的数据 cerr打印错误信息 clog打印日志信息
#include <iostream> using std::cin;using std::cout;using std::endl;using std::cerr; using std::clog;void test0 () { cout<<"cout" <<endl; cerr<<"cerr" "<endl; clog<<" clog"<<endl; } int main() { test0(); }
文件打印结果
错误文件打印结果
当将编译执行后的打印放进文件中,会发现文件中仅有cout输出 当指定编译执行后的打印以标准错误2放进文件中,会发现文件中有cerr,clog
ifstream 用于文件的读功能,属于文件IO内的一种自定义类型
#include <iostream> #include <fstream> #include <string> #include <string.h> using std::cin;using std::cout;using std::endl;using std::cerr; using std::clog;using std::string;using std::ifstream;void test1 () { ifstream ifs ("namespace.cpp" ) ; if (!ifs.good ()) { cout<<"ifstream open failed" <<endl; return ; } string word; while (ifs>>word) { cout<<word<<' ' ; } ifs.close (); } int main () { test1 (); }
注:namespace.cpp是我之前已经写过的一个cpp文件,你们可以选择一个txt类型的文件打开,也是可以的
输出结果
#include <iostream> //using namespace std 以后可以禁掉了 using std ::cin;// :: 作用域限定符 using std ::cout; //using std ::endl; extern int number2;//跨模块调用 //匿名空间内定义的变量无法跨模块调用,与static相同 namespace wd { int num = 1 ; void print () { cout << "print()" << std ::endl; } namespace lr { int num ; void display () { cout << "display" << std ::endl; } }//end of namespace lr }//end of namespace wd namespace//匿名空间直接使用 { int num = 2 ; } namespace wd2 { void print (); }//命名空间内部函数可以像函数一样声明再定义,可以多次定义命名空间 //不同的是,一般函数声明可以多次,但定义只有一次 //命名空间就像容器,可以无限定义实体 //如果函数调用的形参与之前定义的变量重名,所调用的变量的值遵循就近原则 //如果有形参,值就是形参,如果没有,就找最近的之前相应变量的值 int main() { wd::print (); cout << wd::num << std :: endl; wd::lr::display (); cout << num << std ::endl; using namespace wd; print (); cout << number2 << std ::endl; wd2::print (); return 0 ; } namespace wd2 { int abc = 1 ; void print () { cout << abc << std ::endl; } }
可以发现,这样输出的结果不是给人看的,需要一样东西来让他能够一行一行输出出来
在之前C++入门阶段我们接触到一个函数为getline,参数只能传字符数组而不能传string对象,但这也够用
#include <iostream> #include <fstream> #include <string> #include <string.h> using std::cin;using std::cout;using std::endl;using std::cerr;using std::clog;using std::string;using std::ifstream;void test1 () { string filename ("namespace.cpp" ) ; ifstream ifs (filename) ; if (!ifs.good ()) { cout<<"ifstream open file failed" <<endl; return ; } char buff[1024 ] = {0 }; while (ifs.getline (buff,1000 )) { cout<<buff<<endl; memset (buff,0 ,sizeof buff); } ifs.close (); } int main () { test1 (); }
输出结果
#include <iostream> using std::cin;using std::cout;extern int number2;namespace wd{ int num = 1 ;void print () { cout << "print()" << std::endl; } namespace lr { int num; void display () { cout << "display" << std::endl; } } } namespace { int num = 2 ;} namespace wd2{ void print () ; } int main () { wd::print (); cout << wd::num << std :: endl; wd::lr::display (); cout << num << std::endl; using namespace wd; print (); cout << number2 << std::endl; wd2::print (); return 0 ; } namespace wd2{ int abc = 1 ;void print () { cout << abc << std::endl; } }
此时打印的代码就非常可观了
ostream ostream对象用于文件写入
成员函数
ofs,open(string);打开当前目录下的string文件 ofs.write(string,len);//第一个参数为要写入的字符串,第二个参数指定写入到多少长度为止 ofs.tellp();//返回当前流游标位置 ofs.seekp(n);流回到指定位置,0表示起始位置
#include <iostream> #include <fstream> #include <string> #include <string.h> using std::cin;using std::cout;using std::endl;using std::cerr;using std::clog;using std::ifstream;using std::ofstream;using std::fstream;using std::string;void otest () { ofstream ofs; ofs.open ("test.txt" , std::ios::out | std::ios::app); if (!ofs) { cout << "ofstream file open failed" << endl; return ; } ofs << "this is a test" << endl; size_t pos = ofs.tellp (); ofs.write ("this is a new test\n" , strlen ("this is a new test\n" )) << endl; } int main () { otest (); }
fstream fstream能进行读写操作,存在于fstream模板中 既包含ifstream的成员函数,也包含ofstream的成员函数
#include <iostream> #include <fstream> using std::cout;using std::cin;using std::endl;using std::string;using std::fstream;void ftest () { fstream fs ("test.txt" , std::ios::in | std::ios::out | std::ios::app) ; if (!fs) { cout << "fstream file open failed " << endl; return ; } int number = -1 ; for (int i = 0 ; i < 4 ; ++i) { cin >> number; fs << number << ' ' ; } cout << endl; fs.seekp (0 ); char buff[1024 ] = { 0 }; while (fs.getline (buff, sizeof buff)) { cout << buff; memset (buff, 0 , sizeof buff); } fs.close (); } int main () { ftest (); return 0 ; }
字符串IO 模板库
自定义类型 istringstream将字符串转换为其他类型 ostringstream将缓冲区内数据转化为字符串 stringstream
istringstream #include <iostream> #incldue <sstream> using std::cin;using std:;cout;using std::endl;void test0 () { istringstream iss ("1 2 3 4 5 6" ) ; string word; while (iss>>word) { cout<<word<<endl; } } int main () { test0 (); }
ostringstream #include <iostream> #include <sstream> using std::cout;using std::endl;using std::string;using std::istringstream;using std::ostringstream;using std::stringstream;void test1 () { int number = -1 ; int id = 101 ; ostringstream oss; oss << "number:" <<number<<' ' <<"id:" <<id<<endl; string str = oss.str (); cout<<str<<endl; } int main () { test1 (); }
输出结果