输入输出流
读取输入和输出
5.1类型:
- 标准输入/输出:键盘,显示器。
- 文件I/O:对外存磁盘文件为对象。
- 串I/O:对内存中指定空间进行输入/输出。
类名 | 作用 | 头文件 |
---|---|---|
istream | 通用输入流 | iostream |
ostream | 通用输出流 | iostream |
iostream | 通用输入输出流 | iostream |
ifstream | 文件输入流 | fstream |
oftream | 文件输出流 | fstream |
fstream | 文件输入输出流 | fstream |
istringstream | 字符串输入流 | sstream |
ostringstream | 字符串输出流 | sstream |
stringstream | 字符串输入输出流 | sstream |
5.2流的四种状态
-
badbit 表示发生系统级的错误,如不可恢复的读写错误。通常情况下一旦 badbit 被置位,流就无法再使用了。
-
failbit 表示发生可恢复的错误,如期望读取一个int数值,却读出一个字符串等错误。这种问题通常是可以修改的,流还可以继续使用。
-
eofbit表示到达流结尾位置, 流在正常输入输出的情况下结束,会被置为eofbit状态。
-
goodbit 表示流处于有效状态。流在有效状态下,才能正常使用。如果 badbit 、 failbit 和 eofbit 任何一个被置位,则流无法正常使用。
5.3标准输入流/输出流
- 1流提取符 “>>” 从流中提取数据时通常跳过输入流中的空格、 tab 键、换行符等空白字符。只有在输入完数据再按回车键后,该行数据才被送入键盘缓冲区,形成输入流,提取运算符 “>>” 才能从中提取数据。需要注意保证从流中读取数据能正常进行。
void printStreamStatus(std::istream & is){
cout << "is's goodbit:" << is.good() << endl;
cout << "is's badbit:" << is.bad() << endl;
cout << "is's failbit:" << is.fail() << endl;
cout << "is's eofbit:" << is.eof() << endl;
}
void test0(){
printStreamStatus(cin); //goodbit状态
int num;
cin >> num;
cout << "num:" << num << endl;
printStreamStatus(cin); //进行一次输入后再检查cin的状态
}
-
2如果没有进行正确的输入,输入流会进入failbit的状态,无法正常工作,需要恢复流的状态。
查看C++参考文档,需要利用clear和ignore函数配合,实现这个过程
if (!cin.good()) { //恢复流状态 cin.clear(); //需要清空缓冲区 //std::numeric_limits<T>::max() 是 C++ 中的一个模板函数,用于获取类型 T 的最大值。 表示尽可能忽略多的字符,一直到'\n'结束。 //为了避免宏定义冲突,在max和()中间加上()。 cin.ignore((numeric_limits<std::streamsize>::max)(), '\n'); }
-
3完成一个整型的输入
void InputInteger() {
cout << "输入整型:" << endl;
int num = 0;
//逗号表达式整体值为最后一个逗号
//之后的表达式的值
while (cin >> num, !cin.eof()) {
if(cin.bad()) {
cout << "cin has broken!" << endl;
return;
}
else if (cin.fail()) {
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << "请输入一个int类型数据" << endl;
}
else {
cout << "num:" << num << endl;
break;
}
}
}
5.4缓冲机制
-
1类型:
-
缓冲机制分为三种类型:全缓冲、行缓冲和不带缓冲。
全缓冲:在这种情况下,当填满缓冲区后才进行实际 I/O 操作。全缓冲的典型代表是对磁盘文件的读写。
行缓冲:在这种情况下,当在输入和输出中遇到换行符时,执行真正的 I/O 操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的 I/O 操作。典型代表是cin。
不带缓冲:也就是不进行缓冲,有多少数据就刷新多少。标准错误输出 cerr是典型代表,这使得出错信息可以直接尽快地显示出来。
-
2输出缓冲区刷新方式:
- 程序正常执行完。
- 缓冲区满。当缓冲区满了之后,就先刷新当前缓冲区种所有内容。
- 使用操作符显示刷新输出缓冲区,比如endl。endl就是先刷新缓冲区,然后再换行。
-
string str,str1; //1.使用输入操作符读取单词,读取两个单词 cin >> str >> str1; //2.读取一行字符串, string str2; cin.ignore(); // 添加这一行 getline(cin, str2); cout << str2 << endl; //3.读取字符 char ch1; char ch = cin.get(); cout << "ch = " << ch << endl;
-
3操作符
- endl:用来换行,并刷新缓冲区。
- flush:用来直接刷新缓冲区。cout.flush();
-
4标准错误流:cerr
-
#include <unistd.h> void test1(){ cerr << 1; cout << 3; sleep(2); }//直接输出13
5.5文件输入/输出流
-
1构造函数形式
-
ifstream(); explicit ifstream(const char* filename, openmode mode = ios_base::in); explicit ifstream(const string & filename, openmode mode = ios_base::in); ofstream(); explicit ofstream(const char* filename, openmode mode = ios_base::out); explicit ofstream(const string & filename, openmode mode = ios_base::out); fstream(); explicit fstream(const char* filename, openmode mode = ios_base::in|out); explicit fstream(const string & filename, openmode mode = ios_base::in|out);
-
2文件模式
**in **: 输入,文件将允许做读操作;如果文件不存在,打开失败
out : 输出,文件将允许做写操作;如果文件不存在,则直接创建一个.会清空。
app : 追加,写入将始终发生在文件的末尾
ate : 末尾,写入最初在文件的末尾
trunc : 截断,如果打开的文件存在,其内容将被丢弃,其大小被截断为零
binary : 二进制,读取或写入文件的数据为二进制形式
-
3文件输入流对象
-
1可以使用无参构造创建ifstream对象,再使用open函数将这个文件输入流对象与文件绑定(若文件不存在,则文件输入流进入failbit状态);
-
//创建文本输入流对象,再绑定文件 //逐个打印每个字符串 ifstream ifs; ifs.open("a.txt"); string word; while (ifs >> word) { cout << word << endl; } ifs.close();
-
也可以使用有参构造创建ifstream对象,在创建时就将流对象与文件绑定,后续操作这个流对象就可以对文件进行相应操作。
-
ifstream ifs("a.txt"); ifs.close();
-
2按行读取:getline
//c风格,不经常使用 ifstream ifs("test.cc"); //方法一,兼容C的写法,使用较少 char buff[100] = {0}; while(ifs.getline(buff,sizeof(buff))){ cout << buff << endl; memset(buff,0,sizeof(buff)); } //c++风格,使用string void test5() { string line; //头文件string while (std::getline(ifs, line)) { cout << line << endl; } }
- 3读取指定字节数的内容
- read()+seekg()+tellg()
- 通过文件输入流对象读取到的内容交给字符数组,同时需要传入要读取的字符数.
- 例子读取一个文件的全部内容。
void test6() { string fileName = "b.txt"; ifstream ifs(fileName); if (!ifs) { cerr << "ifs open file fail!" << fileName << endl; return; } //读取一个文件要获取文件的大小 //将游标放到文件的最后 ifs.seekg(0, std::ios::end); long length = ifs.tellg(); //获取尾后下标,也就是总的字符数 cout << length << endl; char* pdate = new char[length + 1](); //需要将游标放在起始位置 ifs.seekg(0, std::ios::beg); ifs.read(pdate, length); //content包含了文件所有内容,包括空格等 string content(pdate); cout << "conten:" << content << endl; ifs.close(); }
- 4文件输出流
//文件输出流,如果不存在就创建 void test7() { string fileName = "target.txt"; ofstream ofs(fileName, std::ios::app); string line("hello\n"); //使用<<写入 ofs << line; } //使用write()写入内容 void test8() { ofstream ofs("target.txt", std::ios::app); string line = "kkkk\n"; ofs.write(line.c_str(), line.size()); }
-
5.6字符串输入/输出流
-
1字符串输入流
- 将字符串的内容传输给字符串输入流对象,再通过这个对象进行字符串的处理(解析)
- 通常用来处理字符串内容,比如读取配置文件。
- 例子:将字符串str传给两个int类型。
-
void test9() { string str = "123 456"; int num1 = 0; int num2 = 0; //将字符串内容传递给字符串输入流对象 //头文件sstream //输入流运算符会默认空格符作为分隔符 istringstream iss(str); iss >> num1 >> num2; cout << "num1: " << num1 << endl; cout << "num2: " << num2 << endl; }
-
2.字符串输出流
- 通常的用途就是将各种类型的数据转换成字符串类型。
-
//字符串输出流 void test10() { int num1 = 123; int num2 = 456; ostringstream oss; oss << "num1 = " << num1 << ", num2 = " << num2 << endl; cout << oss.str() << endl; }