
C++中的输入输出(I/O)功能主要由标准库中的iostream库提供。这个库包含了一系列用于处理输入输出操作的类和函数。以下是C++中常用的输入输出(I/O)函数和类的一个简要汇总。
在C++中,基本输入输出对象主要通过<iostream>库提供。这些对象用于在程序与用户之间交换数据,包括从标准输入(如键盘)读取数据,以及向标准输出(如屏幕)写入数据。
std::cout: std::ostream类的一个实例。<<)来输出各种类型的数据。std::cin: std::istream类的一个实例。>>)来读取各种类型的数据。std::cerr: std::cout类似,但通常用于输出错误或警告信息。std::clog: std::cerr类似,也用于输出错误信息,但它是带缓冲的。std::cerr和std::clog都输出到标准错误流,但std::clog的输出可能会被缓冲,直到缓冲区满或显式刷新。虽然std::cout本身不直接提供复杂的格式化选项(除了内置的类型转换和插入运算符的重载),但你可以通过包含<iomanip>头文件来使用额外的格式化功能,如设置字段宽度、精度、填充字符、基数(十进制、十六进制等)等。
#include <iostream>
#include <iomanip> // 对于格式化输出
int main() {
// 输出
std::cout << "Hello, World!" << std::endl;
// 输入
int number;
std::cout << "Enter a number: ";
std::cin >> number;
std::cout << "You entered: " << number << std::endl;
// 错误输出
std::cerr << "This is an error message." << std::endl;
// 格式化输出
double pi = 3.14159;
std::cout << std::fixed << std::setprecision(2) << "Pi is approximately " << pi << std::endl;
return 0;
}
在这个示例中,std::cout用于输出字符串和变量,std::cin用于从用户那里读取一个整数,std::cerr用于输出一个错误信息,而<iomanip>库则用于格式化double类型的输出。
在C++中,输入输出操作符是重载的运算符,用于与输入输出流(如std::cin和std::cout)一起工作,以实现数据的读取和写入。这些操作符主要包括插入操作符(<<)和提取操作符(>>)。
<<)int、float、double、char、char*(C风格字符串)、std::string等),<<操作符都被重载以支持将这些类型的数据输出到流中。#include <iostream>
#include <string>
int main() {
int number = 42;
float pi = 3.14f;
char ch = 'A';
std::string text = "Hello, World!";
std::cout << "Number: " << number << std::endl;
std::cout << "Pi: " << pi << std::endl;
std::cout << "Character: " << ch << std::endl;
std::cout << "Text: " << text << std::endl;
return 0;
}
>>)<<类似,>>也被重载以支持从流中提取不同类型的数据。#include <iostream>
int main() {
int number;
float pi;
char ch;
std::cout << "Enter a number: ";
std::cin >> number;
std::cout << "You entered: " << number << std::endl;
std::cout << "Enter a float: ";
std::cin >> pi;
std::cout << "You entered: " << pi << std::endl;
std::cout << "Enter a character: ";
std::cin >> ch;
std::cout << "You entered: " << ch << std::endl;
return 0;
}
>>从std::cin读取数据时,如果遇到无法转换为请求类型的输入(如非数字字符后跟int类型的读取尝试),输入流会进入错误状态,并且后续的读取操作会失败,直到错误状态被清除。std::cin.clear()来清除错误状态,并通过std::cin.ignore()来忽略错误输入之后的字符,以便继续从输入流中读取数据。std::cin >> stringVariable会在遇到空白字符(空格、制表符、换行符等)时停止读取。如果需要读取整行(包括空格),则应使用std::getline(std::cin, stringVariable)。#include <iostream>
#include <limits>
int main() {
int number;
std::cout << "Enter a number: ";
while (!(std::cin >> number)) {
std::cerr << "Invalid input! Please enter a number." << std::endl;
std::cin.clear(); // 清除错误状态
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 忽略直到下一个换行符的所有字符
std::cout << "Try again: ";
}
std::cout << "You entered: " << number << std::endl;
return 0;
}
C++中格式化输出通常涉及对输出流(如std::cout)的操纵,以控制数字的显示方式(如基数、精度、宽度等)或字符串的格式化。C++标准库提供了几种方式来实现格式化输出,包括使用I/O操纵符(如<iomanip>头文件中的那些)和直接通过流成员函数。
以下是一些常用的格式化输出方法和示例。
<iomanip>头文件<iomanip>头文件包含了一系列用于格式化输出的操纵符,如std::setw、std::setprecision、std::setfill、std::left、std::right、std::internal、std::uppercase、std::lowercase、std::hex、std::oct和std::dec等。
示例
#include <iostream>
#include <iomanip> // 包含格式化操纵符
int main() {
double pi = 3.141592653589793;
// 设置宽度、填充字符和对齐方式
std::cout << std::setw(10) << std::setfill('*') << std::left << "Left:" << pi << std::endl;
std::cout << std::setw(10) << std::setfill('*') << std::right << "Right:" << pi << std::endl;
// 设置精度
std::cout << std::fixed << std::setprecision(3) << "Fixed-point, precision 3: " << pi << std::endl;
// 设置基数
std::cout << std::hex << std::uppercase << "Hexadecimal: " << (int)pi << std::endl; // 注意:pi转换为int会丢失小数部分
std::cout << std::oct << "Octal: " << (int)pi << std::endl;
std::cout << std::dec << "Decimal: " << (int)pi << std::endl;
return 0;
}
虽然<iomanip>提供了大量的格式化选项,但C++流类(如std::ostream)也提供了一些成员函数来直接控制格式化。然而,这些成员函数通常不如<iomanip>中的操纵符直观或常用。
对于更复杂的格式化需求,可能需要编写自定义的代码来格式化数据。这可以通过将数据转换为字符串,并使用字符串操作函数(如std::stringstream)来构建最终的输出字符串来实现。
示例:使用std::stringstream进行自定义格式化
#include <iostream>
#include <sstream>
#include <string>
int main() {
int number = 12345;
std::stringstream ss;
// 自定义格式化
ss << "[" << std::setw(5) << std::setfill('0') << number << "]";
std::string formattedString = ss.str();
std::cout << "Formatted number: " << formattedString << std::endl;
return 0;
}在这个例子中,我们使用std::stringstream来构建一个包含特定格式的数字的字符串。这种方法提供了很大的灵活性,允许我们以几乎任何你想要的方式格式化数据。
C++中的文件输入输出(File I/O)是通过C++标准库中的<fstream>头文件提供的文件流类来完成的。这些类包括ifstream(用于从文件读取数据)、ofstream(用于向文件写入数据)和fstream(同时支持读写操作)。以下是对这些类及其基本用法的汇总和示例。
在打开文件时,可以指定不同的模式,如只读、只写、追加等。这些模式是通过与std::ios_base::openmode枚举值进行按位或(|)操作来指定的。一些常见的模式包括:
std::ios::in:打开文件以进行读取。std::ios::out:打开文件以进行写入。std::ios::app:以追加模式打开文件(写入的数据会被添加到文件末尾)。std::ios::binary:以二进制模式打开文件(默认是文本模式)。std::ios::trunc:如果文件已存在,则先删除文件内容(与std::ios::out一起使用时)。ifstream读取文件#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream file("example.txt"); // 打开文件以进行读取
if (file.is_open()) {
std::string line;
while (getline(file, line)) { // 逐行读取
std::cout << line << '\n';
}
file.close(); // 关闭文件
} else {
std::cerr << "Unable to open file";
}
return 0;
}ofstream写入文件#include <fstream>
#include <iostream>
int main() {
std::ofstream file("output.txt"); // 打开文件以进行写入
if (file.is_open()) {
file << "Hello, World!" << std::endl; // 写入一行文本
file.close(); // 关闭文件
} else {
std::cerr << "Unable to open file";
}
return 0;
}fstream同时读写文件虽然fstream可以同时支持读写操作,但通常建议在明确知道需要同时进行读写操作时才使用它,因为它可能会使代码的逻辑变得更加复杂。
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::fstream file("example.txt", std::ios::in | std::ios::out | std::ios::app); // 以追加和读取模式打开文件
if (file.is_open()) {
// 写入文件(追加模式)
file << "Appending text...\n";
// 假设我们需要回到文件开头读取内容
file.seekg(0, std::ios::beg); // 设置读取位置到文件开头
std::string line;
while (getline(file, line)) { // 逐行读取
std::cout << line << '\n';
}
file.close(); // 关闭文件
} else {
std::cerr << "Unable to open file";
}
return 0;
}注意:在同时读写文件时,需要特别注意文件的打开模式和当前的位置指针(通过seekg和seekp分别控制读取和写入的位置)。
以上示例展示了C++中文件输入输出操作的基本用法。在实际应用中,需要根据具体需求选择适当的文件打开模式和操作方法。
C++中的输入输出流(I/O streams)具有一系列状态标志,这些标志用于表示流的状态,如是否成功执行了操作、是否到达了文件末尾(EOF)、是否发生了错误等。这些状态标志对于控制程序的流程和错误处理非常重要。
在C++中,std::ios_base类定义了流的状态标志,这些标志可以通过位掩码操作来检查和修改。以下是一些常见的状态标志:
std::ios::goodbit:值为0,表示没有错误发生。std::ios::eofbit:设置时表示已经到达文件末尾(EOF)。std::ios::failbit:设置时表示非致命的输入/输出错误,如格式错误。std::ios::badbit:设置时表示致命的输入/输出错误,如无法读取或写入设备。可以通过成员函数来检查流的状态,如good(), eof(), fail(), bad()等。这些函数返回一个布尔值,指示相应的状态标志是否被设置。
good():如果流状态为goodbit(即没有错误),则返回true。eof():如果设置了eofbit(即已到达文件末尾),则返回true。fail():如果设置了failbit或badbit,则返回true。bad():如果设置了badbit,则返回true。可以使用clear()成员函数来清除或设置流的状态标志。它接受一个参数,该参数是std::ios_base::iostate类型的值(即状态标志的按位或组合)。
clear():无参数时,将流的状态设置为goodbit,清除所有错误标志。如果提供了参数,则将该参数指定的状态设置为流的新状态。以下是一个示例,演示了如何检查和处理输入输出流的状态:
#include <iostream>
#include <fstream>
#include <string>
int main() {
std::ifstream file("nonexistent.txt"); // 尝试打开一个不存在的文件
if (!file) {
// 如果文件打开失败(failbit 被设置),则输出错误信息
std::cerr << "Unable to open file" << std::endl;
} else {
std::string line;
while (getline(file, line)) {
// 读取文件内容(这里不会执行,因为文件不存在)
}
if (file.eof()) {
// 如果到达文件末尾(对于不存在的文件,这里不会执行)
std::cout << "Reached end of file" << std::endl;
}
if (file.fail()) {
// 如果发生了非致命的错误(对于不存在的文件,这里会执行)
// 注意:对于文件不存在的情况,failbit 可能会被设置,但这取决于具体的实现
std::cerr << "A non-fatal I/O error occurred" << std::endl;
}
if (file.bad()) {
// 如果发生了致命的错误(这里通常不会执行,除非有硬件级别的错误)
std::cerr << "A fatal I/O error occurred" << std::endl;
}
// 清除所有错误状态,并尝试重新打开文件(这里只是为了示例)
// 注意:对于不存在的文件,这不会改变任何情况
file.clear(); // 清除所有错误标志
// ... 尝试其他操作 ...
file.close(); // 关闭文件(即使之前未能成功打开)
}
return 0;
}注意:在上面的示例中,尝试打开一个不存在的文件会导致failbit被设置,因为无法执行读取操作。然而,eofbit通常不会在这种情况下被设置,因为它表示的是成功读取到文件末尾的状态。此外,badbit很少在正常的文件操作中被设置,它通常与无法恢复的硬件级错误相关联。
在实际应用中,应该根据程序的特定需求和上下文来检查和处理流的状态。
C++中的操纵符(Manipulators)是特殊类型的函数或对象,它们被用来改变流(如std::cin、std::cout、文件流等)的状态或行为。这些操纵符通常用于格式化输出,但也可以用于输入流中,尽管这在实践中较少见。下面是一些常见的C++操纵符及其示例。
std::endlstd::endl是一个操纵符,用于在输出流中插入一个换行符,并刷新输出缓冲区。它通常与std::cout一起使用。
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
// 输出:Hello, World!
// 然后换行,并刷新输出缓冲区
return 0;
}
std::flushstd::flush是一个操纵符,用于刷新输出缓冲区,但不插入换行符。
#include <iostream>
int main() {
std::cout << "This will be output immediately: ";
std::cout.flush(); // 或者 std::flush(std::cout);
// 输出:"This will be output immediately: " 并立即显示在屏幕上
// 注意:这里没有换行
return 0;
}
std::fixed 和 std::scientific这两个操纵符用于控制浮点数的输出格式。std::fixed以定点表示法输出浮点数,而std::scientific以科学记数法输出。
#include <iostream>
#include <iomanip> // 对于setprecision
int main() {
double pi = 3.141592653589793;
std::cout << std::fixed << pi << std::endl; // 定点表示法
std::cout << std::scientific << pi << std::endl; // 科学记数法
// 输出可能类似于:
// 3.141593
// 3.141593e+00
return 0;
}
std::setprecisionstd::setprecision是一个操纵符,用于设置浮点数的精度(小数点后的位数)。它通常与std::fixed或std::scientific一起使用来精确控制浮点数的输出格式。
#include <iostream>
#include <iomanip>
int main() {
double pi = 3.141592653589793;
std::cout << std::fixed << std::setprecision(5) << pi << std::endl; // 定点表示法,5位小数
// 输出:3.14159
std::cout << std::scientific << std::setprecision(3) << pi << std::endl; // 科学记数法,3位有效数字
// 输出可能类似于:3.14e+00,具体取决于实现
return 0;
}
std::setwstd::setw是一个操纵符,用于设置下一个输出字段的最小宽度。如果输出的内容少于指定的宽度,则默认会在前面填充空格(但可以通过其他操纵符如std::setfill来改变填充字符)。
#include <iostream>
#include <iomanip>
int main() {
std::cout << std::setw(10) << 123 << std::endl; // 输出: 123
// 注意前面的空格,使得整个输出宽度为10
return 0;
}
std::setfillstd::setfill是一个操纵符,用于设置std::setw操纵符用于填充的字符。默认情况下,填充字符是空格。
#include <iostream>
#include <iomanip>
int main() {
std::cout << std::setw(10) << std::setfill('*') << 123 << std::endl; // 输出:*******123
// 使用'*'作为填充字符
return 0;
}C++中的输入输出(I/O)操作涉及到缓冲机制,这是为了提高效率而设计的。缓冲允许程序将数据累积在内存中的一个临时区域(即缓冲区)中,然后再一次性地将数据写入到其最终目的地(如文件、控制台等)或从那里读取数据。这样可以减少物理设备的访问次数,因为物理设备的访问速度通常远低于内存访问速度。
在C++中,主要有两种类型的缓冲:
std::endl或std::flush)时,才会将数据写入到其最终目的地。文件流(如std::ifstream、std::ofstream)通常使用全缓冲。
std::cout)通常与终端(控制台)关联时采用行缓冲模式。
std::cerr)通常是无缓冲的,以确保错误信息能够立即被用户看到。
以下是一些关于C++中缓冲的示例:
示例1:使用std::endl刷新缓冲区
#include <iostream>
int main() {
std::cout << "Hello, ";
// 此时,Hello, 可能还在缓冲区中,尚未输出到控制台
std::cout << "World!" << std::endl;
// 使用std::endl不仅插入了换行符,还刷新了缓冲区,所以Hello, World!现在被输出到控制台
return 0;
}
示例2:显式刷新缓冲区
#include <iostream>
int main() {
std::cout << "Hello, ";
// 显式刷新缓冲区,确保Hello, 被输出到控制台
std::cout.flush();
std::cout << "World!";
// World! 随后被输出到控制台,但不需要显式刷新,因为当main函数结束时,std::cout的析构函数会刷新缓冲区
return 0;
}
示例3:文件流的缓冲
文件流(如std::ofstream)使用全缓冲。这意味着,直到缓冲区满或文件被关闭(或显式刷新)之前,数据可能不会写入到文件中。
#include <fstream>
int main() {
std::ofstream file("example.txt");
if (file.is_open()) {
file << "Hello, World!";
// 此时,Hello, World! 可能还在缓冲区中,尚未写入到文件
file.close(); // 关闭文件时,会刷新缓冲区并将数据写入到文件中
// 或者可以显式地调用 file.flush(); 来刷新缓冲区
}
return 0;
}std::cout可能与标准错误流(std::cerr)一样是无缓冲的,而在其他系统上则可能是行缓冲的。C++中的字符串流(String Streams)提供了一种方便的方式来对字符串进行输入输出操作,就像它们是文件流或控制台流一样。字符串流定义在<sstream>头文件中,主要包括三种类型:istringstream(用于从字符串中读取数据)、ostringstream(用于向字符串中写入数据)和stringstream(同时支持读写操作)。
std::istringstream:从字符串中读取数据。std::ostringstream:向字符串中写入数据。std::stringstream:同时支持从字符串中读取数据和向字符串中写入数据。示例1:使用std::ostringstream构建字符串
#include <sstream>
#include <string>
#include <iostream>
int main() {
std::ostringstream oss;
oss << "Hello, " << "World!" << " " << 42;
std::string result = oss.str(); // 获取构建的字符串
std::cout << result << std::endl; // 输出:Hello, World! 42
return 0;
}
示例2:使用std::istringstream解析字符串
#include <sstream>
#include <string>
#include <iostream>
int main() {
std::string data = "123 456.789 Hello";
std::istringstream iss(data);
int intValue;
double doubleValue;
std::string strValue;
iss >> intValue >> doubleValue >> strValue;
std::cout << "Integer: " << intValue << std::endl;
std::cout << "Double: " << doubleValue << std::endl;
std::cout << "String: " << strValue << std::endl;
// 输出:
// Integer: 123
// Double: 456.789
// String: Hello
return 0;
}
示例3:使用std::stringstream进行读写操作
#include <sstream>
#include <string>
#include <iostream>
int main() {
std::stringstream ss;
// 写入数据
ss << "Hello, " << "World!";
// 读取数据
std::string greeting;
ss >> greeting; // 读取"Hello,"
// 清除错误标志和填充缓冲区,以便重新使用流
ss.clear();
std::string discard;
std::getline(ss, discard, ','); // 读取并丢弃逗号
std::getline(ss, greeting); // 读取剩余部分" World!"
std::cout << greeting << std::endl; // 输出: World!
return 0;
}
std::istringstream或std::stringstream进行读取操作时,如果输入格式与期望的格式不匹配,流将进入错误状态。在这种情况下,可以使用stream.clear()来清除错误状态,并继续使用流进行其他操作。std::getline()函数在读取时遇到换行符(\n)会停止读取,但在std::istringstream或std::stringstream中,可以使用第三个参数来指定其他停止字符,如示例3中所示。类别 | 描述 | 示例/用法 |
|---|---|---|
基本输入输出对象 | ||
std::cin | 用于从标准输入(通常是键盘)读取数据。 | std::cin >> x; |
std::cout | 用于向标准输出(通常是屏幕)输出数据。 | std::cout << "Hello, World!" << std::endl; |
std::cerr | 用于输出错误信息,通常不经过缓冲区,直接输出。 | std::cerr << "Error!" << std::endl; |
std::clog | 用于输出日志信息,和std::cerr类似,但可以被重定向。 | std::clog << "Log information." << std::endl; |
输入输出操作符 | ||
<< (插入操作符) | 向输出流中插入数据。 | std::cout << "Hello, World!" << std::endl; |
>> (提取操作符) | 从输入流中提取数据。 | std::cin >> x; |
格式化输出 | ||
std::setw(int n) | 设置下一个输出项的宽度为n个字符。 | std::cout << std::setw(10) << x << std::endl; |
std::setfill(char c) | 设置填充字符,与std::setw结合使用。 | std::cout << std::setw(10) << std::setfill('*') << x << std::endl; |
std::setprecision(int n) | 设置浮点数输出的精度或小数点后的位数。 | std::cout << std::setprecision(5) << x << std::endl; |
std::fixed | 以定点表示法输出浮点数。 | std::cout << std::fixed << x << std::endl; |
std::scientific | 以科学记数法输出浮点数。 | std::cout << std::scientific << x << std::endl; |
文件输入输出 | ||
std::ifstream | 用于从文件读取数据。 | std::ifstream file("example.txt"); |
std::ofstream | 用于向文件写入数据。 | std::ofstream file("output.txt"); |
std::fstream | 同时支持读写文件的类。 | `std::fstream file("file.txt", std::ios::in |
输入输出流状态 | ||
good() | 检查流状态是否良好。 | if (file.good()) { /* 操作 */ } |
eof() | 检查是否到达文件末尾(EOF)。 | if (file.eof()) { /* 处理EOF */ } |
fail() | 检查流是否因为错误而失败。 | if (file.fail()) { /* 处理错误 */ } |
bad() | 检查流是否已损坏(如读取失败)。 | if (file.bad()) { /* 处理损坏 */ } |
clear() | 重置流的状态标志。 | file.clear(); |
操纵符 | ||
std::endl | 在输出流中插入换行符,并刷新输出缓冲区。 | std::cout << "Hello" << std::endl; |
std::flush | 刷新输出缓冲区,但不插入换行符。 | std::cout << "Hello" << std::flush; |
std::hex、std::oct、std::dec | 设置或重置用于整数输出的基数(十六进制、八进制、十进制)。 | std::cout << std::hex << x << std::endl; |
输入输出缓冲 | ||
缓冲区 | 临时存储输入输出数据的内存区域。 | std::cout << std::flush; 或 file.flush(); |
字符串流 | ||
std::istringstream | 从字符串读取数据的输入流。 | std::istringstream iss("123 456"); |
std::ostringstream | 向字符串写入数据的输出流。 | std::ostringstream oss; oss << "Hello"; |
std::stringstream | 同时支持读写字符串的流。 | std::stringstream ss; ss << "Hello"; ss >> x; |