8.1 IO类
C++标准库提供了一套丰富的输入输出(IO)类,用于处理数据的输入输出操作。这些类位于<iostream>
头文件中,包括处理标准输入输出的istream
和ostream
类,处理文件输入输出的ifstream
和ofstream
类,以及处理字符串流的istringstream
和ostringstream
类。
8.1.1 istream和ostream
istream
类和ostream
类分别用于处理输入和输出操作。cin
是istream
类的对象,用于从标准输入读取数据,cout
是ostream
类的对象,用于向标准输出写入数据。
示例代码
#include <iostream>int main() {int number;std::cout << "Enter a number: ";std::cin >> number; // 从标准输入读取数据std::cout << "You entered: " << number << std::endl; // 向标准输出写入数据return 0;
}
在这个示例中,使用cin
从标准输入读取一个整数,并使用cout
将其输出到标准输出。
8.1.2 ifstream和ofstream
ifstream
类和ofstream
类分别用于处理文件的输入和输出操作。通过创建这些类的对象,可以打开文件进行读写操作。
示例代码
#include <iostream>
#include <fstream>
#include <string>int main() {// 写入文件std::ofstream outFile("example.txt");if (outFile.is_open()) {outFile << "Hello, world!" << std::endl;outFile.close();} else {std::cerr << "Unable to open file for writing" << std::endl;}// 读取文件std::ifstream inFile("example.txt");if (inFile.is_open()) {std::string line;while (std::getline(inFile, line)) {std::cout << line << std::endl;}inFile.close();} else {std::cerr << "Unable to open file for reading" << std::endl;}return 0;
}
在这个示例中,使用ofstream
对象将字符串写入文件,然后使用ifstream
对象从文件读取字符串并输出到标准输出。
8.1.3 stringstream
istringstream
类和ostringstream
类分别用于处理字符串的输入和输出操作。这些类允许我们将字符串视为一个输入输出流进行处理。
示例代码
#include <iostream>
#include <sstream>
#include <string>int main() {std::string data = "123 456 789";std::istringstream iss(data);int a, b, c;iss >> a >> b >> c; // 从字符串流中读取数据std::cout << "Read from stringstream: " << a << " " << b << " " << c << std::endl;std::ostringstream oss;oss << a << " " << b << " " << c; // 向字符串流中写入数据std::string result = oss.str();std::cout << "Written to stringstream: " << result << std::endl;return 0;
}
在这个示例中,使用istringstream
对象从字符串中读取整数,然后使用ostringstream
对象将整数写入到另一个字符串中。
8.1.4 IO操作的条件状态
在进行IO操作时,了解并处理流的状态非常重要。流的状态可以通过以下成员函数来检查(完整的函数请参见书本P279中的表8.2):
good()
: 流未发生错误eof()
: 已到达文件末尾fail()
: 读/写操作失败bad()
: 流已崩溃
每个流对象都包含一个iostate
类型的值来表示当前的状态。
示例代码
#include <iostream>
#include <fstream>int main() {std::ifstream inFile("example.txt");if (!inFile) {std::cerr << "Unable to open file for reading" << std::endl;return 1;}int number;while (inFile >> number) {std::cout << "Read number: " << number << std::endl;}if (inFile.eof()) {std::cout << "End of file reached" << std::endl;} else if (inFile.fail()) {std::cerr << "Read failure" << std::endl;} else if (inFile.bad()) {std::cerr << "Bad file stream" << std::endl;}inFile.close();return 0;
}
在这个示例中,检查了inFile
对象的状态,确保正确处理文件读取过程中可能发生的错误。
8.1.5 管理输出缓冲
输出缓冲是为了提高IO效率,将数据暂存于缓冲区,然后在适当时刻(如缓冲区满或遇到换行符)将数据输出到目的地。可以使用以下方法控制输出缓冲:
flush()
: 强制刷新缓冲区,将所有缓冲区内容写入目的地。ends
: 插入一个空字符,然后刷新缓冲区。endl
: 插入一个换行符,然后刷新缓冲区。
示例代码
#include <iostream>
#include <fstream>int main() {std::ofstream outFile("example.txt");if (!outFile) {std::cerr << "Unable to open file for writing" << std::endl;return 1;}outFile << "Hello, " << std::flush;outFile << "world!" << std::endl;outFile.close();return 0;
}
在这个示例中,使用flush
和endl
控制输出缓冲,将数据及时写入文件。
重点与难点分析
重点:
- 标准输入输出流:掌握
cin
和cout
的基本使用方法,理解它们在标准输入输出中的作用。 - 文件输入输出流:掌握
ifstream
和ofstream
的使用方法,理解文件读写操作的基本流程。 - 字符串流:理解
istringstream
和ostringstream
的作用,掌握使用字符串流进行数据处理的方法。 - IO操作的条件状态:理解流的状态检查方法,掌握处理IO操作错误的方法。
- 管理输出缓冲:掌握控制输出缓冲的方法,理解
flush
、ends
和endl
的使用场景。
难点:
- 文件操作的错误处理:理解文件操作中的错误处理机制,掌握如何检查文件打开是否成功以及如何处理读写错误。
- 字符串流的应用:掌握字符串流在复杂字符串处理中的应用,提高对字符串数据的处理能力。
- 流的状态管理:熟悉各种流状态的含义和使用场景,掌握处理不同状态的技巧。
- 输出缓冲的控制:理解输出缓冲的机制,掌握在不同场景下合理使用
flush
、ends
和endl
的方法。
练习题解析
- 练习8.1:编写一个程序,使用
cin
从标准输入读取一个整数,并使用cout
将其输出到标准输出。
-
- 示例代码:
#include <iostream>int main() {int number;std::cout << "Enter a number: ";std::cin >> number;std::cout << "You entered: " << number << std::endl;return 0;
}
- 练习8.2:编写一个程序,使用
ofstream
将一段文本写入到文件中,然后使用ifstream
从该文件读取文本并输出到标准输出。
-
- 示例代码:
#include <iostream>
#include <fstream>
#include <string>int main() {std::ofstream outFile("example.txt");if (outFile.is_open()) {outFile << "This is a test." << std::endl;outFile.close();} else {std::cerr << "Unable to open file for writing" << std::endl;}std::ifstream inFile("example.txt");if (inFile.is_open()) {std::string line;while (std::getline(inFile, line)) {std::cout << line << std::endl;}inFile.close();} else {std::cerr << "Unable to open file for reading" << std::endl;}return 0;
}
- 练习8.3:编写一个程序,使用
istringstream
从字符串中提取整数,并使用ostringstream
将这些整数重新组合成一个字符串。
-
- 示例代码:
#include <iostream>
#include <sstream>
#include <string>int main() {std::string data = "10 20 30";std::istringstream iss(data);int a, b, c;iss >> a >> b >> c;std::ostringstream oss;oss << "The numbers are: " << a << ", " << b << ", " << c;std::string result = oss.str();std::cout << result << std::endl;return 0;
}
- 练习8.4:编写一个程序,使用
ifstream
读取文件中的整数,并检查读取操作的条件状态。
-
- 示例代码:
#include <iostream>
#include <fstream>int main() {std::ifstream inFile("numbers.txt");if (!inFile) {std::cerr << "Unable to open file for reading" << std::endl;return 1;}int number;while (inFile >> number) {std::cout << "Read number: " << number << std::endl;}if (inFile.eof()) {std::cout << "End of file reached" << std::endl;} else if (inFile.fail()) {std::cerr << "Read failure" << std::endl;} else if (inFile.bad()) {std::cerr << "Bad file stream" << std::endl;}inFile.close();return 0;
}
- 练习8.5:编写一个程序,使用
ofstream
将数据写入文件,并使用flush
和endl
管理输出缓冲。
-
- 示例代码:
#include <iostream>
#include <fstream>int main() {std::ofstream outFile("example.txt");if (!outFile) {std::cerr << "Unable to open file for writing" << std::endl;return 1;}outFile << "Hello, " << std::flush;outFile << "world!" << std::endl;outFile.close();return 0;
}
总结与提高
本节总结:
- 学习了标准库中的输入输出类,理解了
istream
和ostream
的基本使用方法。 - 掌握了文件输入输出操作,理解了
ifstream
和ofstream
的基本使用方法。 - 了解了字符串流的使用,掌握了
istringstream
和ostringstream
在字符串处理中的应用。 - 理解了IO操作的条件状态,掌握了如何检查和处理IO操作中的错误。
- 学习了管理输出缓冲的方法,掌握了
flush
、ends
和endl
的使用。
提高建议:
- 多练习文件操作:通过编写更多涉及文件读写操作的程序,熟悉文件操作的流程和错误处理机制。
- 深入理解字符串流:通过实践掌握字符串流在复杂数据处理中的应用,提高字符串数据处理能力。
- 扩展IO库的使用:探索更多标准库提供的IO类,如
fstream
、stringstream
等,理解它们在不同场景中的应用。 - 加强流状态管理:通过实际操作和代码调试,熟悉流状态的检查和管理方法,处理IO操作中的各种异常情况。
- 灵活使用输出缓冲:在不同场景下合理使用
flush
、ends
和endl
,提高程序的输出效率和效果。
8.2 文件输入输出
在C++中,文件输入输出(File I/O)是通过标准库提供的<fstream>
头文件中的类来实现的。主要的类有ifstream
(输入文件流)、ofstream
(输出文件流)和fstream
(输入输出文件流)。这些类使得文件的读写操作变得简单和方便。
8.2.1 打开和关闭文件
使用文件流对象之前,需要先打开文件。在使用完成后,应该关闭文件以释放资源。可以通过构造函数或者open
方法来打开文件,通过close
方法来关闭文件。
示例代码
#include <iostream>
#include <fstream>
#include <string>int main() {// 打开文件进行写操作std::ofstream outFile("example.txt");if (outFile.is_open()) {outFile << "Hello, world!" << std::endl;outFile.close(); // 关闭文件} else {std::cerr << "Unable to open file for writing" << std::endl;}// 打开文件进行读操作std::ifstream inFile("example.txt");if (inFile.is_open()) {std::string line;while (std::getline(inFile, line)) {std::cout << line << std::endl;}inFile.close(); // 关闭文件} else {std::cerr << "Unable to open file for reading" << std::endl;}return 0;
}
在这个示例中,使用ofstream
对象打开文件进行写操作,并在写入完成后关闭文件。然后使用ifstream
对象打开同一个文件进行读操作,并在读取完成后关闭文件。
8.2.2 文件模式
在打开文件时,可以指定文件模式(mode)以控制文件的打开方式。常见的文件模式包括:
ios::in
:以读模式打开文件ios::out
:以写模式打开文件ios::app
:以追加模式打开文件ios::ate
:以追加模式打开文件,并将文件指针移动到文件末尾ios::trunc
:如果文件已存在,先清空文件内容ios::binary
:以二进制模式打开文件
可以通过使用位运算符|
组合多个文件模式。
示例代码
#include <iostream>
#include <fstream>int main() {// 以写模式打开文件,如果文件已存在,则清空文件内容std::ofstream outFile("example.txt", std::ios::out | std::ios::trunc);if (outFile.is_open()) {outFile << "Writing to file in write mode." << std::endl;outFile.close();} else {std::cerr << "Unable to open file for writing" << std::endl;}// 以追加模式打开文件,文件指针在文件末尾std::ofstream appendFile("example.txt", std::ios::out | std::ios::app);if (appendFile.is_open()) {appendFile << "Appending to file." << std::endl;appendFile.close();} else {std::cerr << "Unable to open file for appending" << std::endl;}return 0;
}
在这个示例中,首先以写模式打开文件,如果文件已存在,则清空文件内容。然后以追加模式打开文件,并在文件末尾追加内容。
8.2.3 读写二进制文件
除了文本文件,C++也支持二进制文件的读写操作。可以使用ios::binary
模式打开文件,并使用write
和read
成员函数进行二进制数据的写入和读取。
示例代码
#include <iostream>
#include <fstream>int main() {// 以二进制模式写入文件std::ofstream outFile("binary.dat", std::ios::out | std::ios::binary);if (outFile.is_open()) {int number = 12345;outFile.write(reinterpret_cast<char*>(&number), sizeof(number));outFile.close();} else {std::cerr << "Unable to open file for writing in binary mode" << std::endl;}// 以二进制模式读取文件std::ifstream inFile("binary.dat", std::ios::in | std::ios::binary);if (inFile.is_open()) {int number;inFile.read(reinterpret_cast<char*>(&number), sizeof(number));std::cout << "Read number: " << number << std::endl;inFile.close();} else {std::cerr << "Unable to open file for reading in binary mode" << std::endl;}return 0;
}
在这个示例中,使用ofstream
对象以二进制模式打开文件,并写入一个整数。然后使用ifstream
对象以二进制模式打开同一个文件,并读取该整数。
8.2.4 文件定位
在文件读写操作中,可以通过文件定位操作(seek)移动文件指针,以便在文件的不同位置进行读写。常用的文件定位操作有:
seekg
:用于输入流,移动文件指针到指定位置seekp
:用于输出流,移动文件指针到指定位置tellg
:用于输入流,返回文件指针的当前位置tellp
:用于输出流,返回文件指针的当前位置
示例代码
#include <iostream>
#include <fstream>int main() {// 写入文件std::ofstream outFile("example.txt");if (outFile.is_open()) {outFile << "0123456789";outFile.close();} else {std::cerr << "Unable to open file for writing" << std::endl;}// 读取文件std::ifstream inFile("example.txt");if (inFile.is_open()) {char ch;inFile.seekg(5); // 将文件指针移动到第5个字符inFile.get(ch);std::cout << "Character at position 5: " << ch << std::endl;inFile.close();} else {std::cerr << "Unable to open file for reading" << std::endl;}return 0;
}
在这个示例中,首先写入一串字符到文件,然后将文件指针移动到文件的第5个字符处,并读取该字符。
重点与难点分析
重点:
- 文件打开和关闭:掌握通过构造函数或
open
方法打开文件,通过close
方法关闭文件。 - 文件模式:理解不同的文件模式及其组合使用,掌握控制文件打开方式的方法。
- 二进制文件读写:掌握使用
ios::binary
模式读写二进制文件的方法,理解write
和read
成员函数的用法。 - 文件定位:理解文件指针的移动和定位方法,掌握
seekg
、seekp
、tellg
和tellp
的使用。
难点:
- 错误处理:理解文件操作中的错误处理机制,掌握如何检查文件打开是否成功以及如何处理读写错误。
- 文件指针定位:熟悉文件指针的移动和定位方法,掌握在不同位置进行读写操作的技巧。
练习题解析
- 练习8.6:编写一个程序,使用
ofstream
将一段文本写入到文件中,然后使用ifstream
从该文件读取文本并输出到标准输出。
-
- 示例代码:
#include <iostream>
#include <fstream>
#include <string>int main() {std::ofstream outFile("example.txt");if (outFile.is_open()) {outFile << "This is a test." << std::endl;outFile.close();} else {std::cerr << "Unable to open file for writing" << std::endl;}std::ifstream inFile("example.txt");if (inFile.is_open()) {std::string line;while (std::getline(inFile, line)) {std::cout << line << std::endl;}inFile.close();} else {std::cerr << "Unable to open file for reading" << std::endl;}return 0;
}
- 练习8.7:编写一个程序,使用
ofstream
将整数写入二进制文件,然后使用ifstream
从该二进制文件读取整数并输出到标准输出。
-
- 示例代码:
#include <iostream>
#include <fstream>int main() {std::ofstream outFile("binary.dat", std::ios::out | std::ios::binary);if (outFile.is_open()) {int number = 12345;outFile.write(reinterpret_cast<char*>(&number), sizeof(number));outFile.close();} else {std::cerr << "Unable to open file for writing in binary mode" << std::endl;}std::ifstream inFile("binary.dat", std::ios::in | std::ios::binary);if (inFile.is_open()) {int number;inFile.read(reinterpret_cast<char*>(&number), sizeof(number));std::cout << "Read number: " << number << std::endl;inFile.close();} else {std::cerr << "Unable to open file for reading in binary mode" << std::endl;}return 0;
}
- 练习8.8:编写一个程序,使用
ofstream
将一串字符写入文件,然后使用ifstream
将文件指针移动到指定位置并读取字符。
-
- 示例代码:
#include <iostream>
#include <fstream>int main() {std::ofstream outFile("example.txt");if (outFile.is_open()) {outFile << "0123456789";outFile.close();} else {std::cerr << "Unable to open file for writing" << std::endl;}std::ifstream inFile("example.txt");if (inFile.is_open()) {char ch;inFile.seekg(5); // 将文件指针移动到第5个字符inFile.get(ch);std::cout << "Character at position 5: " << ch << std::endl;inFile.close();} else {std::cerr << "Unable to open file for reading" << std::endl;}return 0;
}
- 练习8.9:编写一个程序,使用
ofstream
将数据写入文件,使用flush
和endl
管理输出缓冲,然后使用ifstream
读取文件内容并输出到标准输出。
-
- 示例代码:
#include <iostream>
#include <fstream>int main() {std::ofstream outFile("example.txt");if (!outFile) {std::cerr << "Unable to open file for writing" << std::endl;return 1;}outFile << "Hello, " << std::flush;outFile << "world!" << std::endl;outFile.close();std::ifstream inFile("example.txt");if (inFile.is_open()) {std::string line;while (std::getline(inFile, line)) {std::cout << line << std::endl;}inFile.close();} else {std::cerr << "Unable to open file for reading" << std::endl;}return 0;
}
总结与提高
本节总结:
- 学习了文件输入输出操作,掌握了
ifstream
和ofstream
的基本使用方法。 - 理解了不同的文件模式及其组合使用,掌握了控制文件打开方式的方法。
- 掌握了使用
ios::binary
模式读写二进制文件的方法,理解了write
和read
成员函数的用法。 - 理解了文件指针的移动和定位方法,掌握了
seekg
、seekp
、tellg
和tellp
的使用。
提高建议:
- 多练习文件操作:通过编写更多涉及文件读写操作的程序,熟悉文件操作的流程和错误处理机制。
- 深入理解文件模式:通过实践掌握不同文件模式的应用场景,提高文件读写操作的灵活性。
- 加强二进制文件读写能力:在实际项目中应用二进制文件读写,提高对复杂数据的处理能力。
- 灵活使用文件定位:通过实际操作和代码调试,掌握文件指针的移动和定位方法,在不同位置进行高效的读写操作。
8.3 string流
在C++中,string流(string stream)提供了一种在内存中操作字符串的机制。它允许我们将字符串看作一个输入输出流,使用类似文件或标准输入输出流的操作来处理字符串。标准库中的istringstream
和ostringstream
类分别用于处理字符串的输入和输出操作,而stringstream
类则兼具输入和输出功能。
8.3.1 istringstream
istringstream
类用于从字符串中读取数据。它的用法类似于ifstream
,但数据来源是字符串而不是文件。
示例代码
#include <iostream>
#include <sstream>
#include <string>int main() {std::string data = "123 456 789";std::istringstream iss(data);int a, b, c;iss >> a >> b >> c;std::cout << "Read from stringstream: " << a << " " << b << " " << c << std::endl;return 0;
}
在这个示例中,istringstream
对象iss
从字符串data
中读取三个整数,并将其输出到标准输出。
8.3.2 ostringstream
ostringstream
类用于向字符串中写入数据。它的用法类似于ofstream
,但数据目的地是字符串而不是文件。
示例代码
#include <iostream>
#include <sstream>int main() {int a = 123, b = 456, c = 789;std::ostringstream oss;oss << a << " " << b << " " << c;std::string result = oss.str();std::cout << "Written to stringstream: " << result << std::endl;return 0;
}
在这个示例中,ostringstream
对象oss
将三个整数写入到字符串中,并将结果字符串输出到标准输出。
8.3.3 stringstream
stringstream
类兼具istringstream
和ostringstream
的功能,可以同时进行字符串的输入和输出操作。
示例代码
#include <iostream>
#include <sstream>int main() {std::stringstream ss;ss << "Initial string content. ";int num = 42;ss << num;std::string output;ss >> output;std::cout << "Output from stringstream: " << output << std::endl;return 0;
}
在这个示例中,stringstream
对象ss
首先将字符串写入流中,然后将整数num
写入流中。随后,从流中读取一个单词并输出。
8.3.4 string流的应用
string流在数据转换、格式化输出和解析复杂字符串等场景中非常有用。例如,可以使用string流将各种类型的数据转换为字符串,或将字符串解析为各种类型的数据。
示例代码
#include <iostream>
#include <sstream>
#include <string>int main() {// 将各种数据类型转换为字符串int num = 123;double pi = 3.14;std::string text = "Hello";std::ostringstream oss;oss << "Number: " << num << ", Pi: " << pi << ", Text: " << text;std::string result = oss.str();std::cout << "Formatted string: " << result << std::endl;// 将字符串解析为各种数据类型std::string data = "42 3.14159 hello";std::istringstream iss(data);int i;double d;std::string s;iss >> i >> d >> s;std::cout << "Parsed values - Integer: " << i << ", Double: " << d << ", String: " << s << std::endl;return 0;
}
在这个示例中,使用string流将整数、浮点数和字符串转换为格式化字符串,然后将字符串解析为整数、浮点数和字符串。
重点与难点分析
重点:
- istringstream:掌握
istringstream
的基本使用方法,理解其在从字符串中读取数据时的作用。 - ostringstream:掌握
ostringstream
的基本使用方法,理解其在向字符串中写入数据时的作用。 - stringstream:掌握
stringstream
的基本使用方法,理解其在同时进行字符串输入和输出时的作用。
难点:
- 字符串流的使用场景:理解在何种场景下使用字符串流能够提高程序的灵活性和可维护性。
- 数据类型转换和解析:掌握使用字符串流进行各种数据类型的转换和解析,提高字符串数据处理能力。
练习题解析
- 练习8.10:编写一个程序,使用
istringstream
从字符串中读取多个整数,并将其输出到标准输出。
-
- 示例代码:
#include <iostream>
#include <sstream>
#include <string>int main() {std::string data = "10 20 30 40 50";std::istringstream iss(data);int number;while (iss >> number) {std::cout << "Read number: " << number << std::endl;}return 0;
}
- 练习8.11:编写一个程序,使用
ostringstream
将多个数据写入到字符串中,并将结果字符串输出到标准输出。
-
- 示例代码:
#include <iostream>
#include <sstream>int main() {std::ostringstream oss;int a = 1, b = 2, c = 3;oss << "Numbers: " << a << ", " << b << ", " << c;std::string result = oss.str();std::cout << "Resulting string: " << result << std::endl;return 0;
}
- 练习8.12:编写一个程序,使用
stringstream
同时进行字符串的输入和输出操作。
-
- 示例代码:
#include <iostream>
#include <sstream>
#include <string>int main() {std::stringstream ss;ss << "Example string with number: " << 100;std::string word;int number;ss >> word >> word >> word >> word >> number;std::cout << "Extracted word: " << word << std::endl;std::cout << "Extracted number: " << number << std::endl;return 0;
}
- 练习8.13:编写一个程序,使用字符串流将不同类型的数据转换为字符串,并将字符串解析为不同类型的数据。
-
- 示例代码:
#include <iostream>
#include <sstream>
#include <string>int main() {// 将数据转换为字符串int age = 25;double height = 5.9;std::string name = "John";std::ostringstream oss;oss << "Name: " << name << ", Age: " << age << ", Height: " << height;std::string result = oss.str();std::cout << "Formatted string: " << result << std::endl;// 将字符串解析为数据std::istringstream iss(result);std::string label;std::string parsedName;int parsedAge;double parsedHeight;iss >> label >> parsedName >> label >> parsedAge >> label >> parsedHeight;std::cout << "Parsed name: " << parsedName << std::endl;std::cout << "Parsed age: " << parsedAge << std::endl;std::cout << "Parsed height: " << parsedHeight << std::endl;return 0;
}
总结与提高
本节总结:
- 学习了
istringstream
的使用,掌握了从字符串中读取数据的方法。 - 学习了
ostringstream
的使用,掌握了向字符串中写入数据的方法。 - 掌握了
stringstream
的使用,理解了其在同时进行字符串输入和输出操作中的作用。 - 理解了string流在数据转换和字符串解析中的应用,提高了处理复杂字符串数据的能力。
提高建议:
- 多练习字符串流操作:通过编写涉及字符串流操作的程序,熟悉
istringstream
、ostringstream
和stringstream
的使用方法。 - 掌握数据转换和解析技巧:通过实践掌握使用字符串流进行数据转换和解析的技巧,提高处理复杂数据的能力。
- 扩展字符串流的应用场景:在实际项目中应用字符串流进行数据处理,提高程序的灵活性和可维护性。
本主页会定期更新,为了能够及时获得更新,敬请关注我:点击左下角的关注。也可以关注公众号:请在微信上搜索公众号“iShare爱分享”并关注,或者扫描以下公众号二维码关注,以便在内容更新时直接向您推送。