电池贪吃蛇
48.39MB · 2025-09-24
C++ 中的 I/O 流 和 文件操作 是处理输入输出的重要工具。C++ 标准库提供了丰富的类和函数,用于从控制台、文件和其他设备读取和写入数据。
流是字节序列。如果字节流是从设备流向内存,这叫做输入操作。如果字节流是从内存流向设备,这叫做输出操作。
学过 C 语言的读者应该知道,它有一整套完成数据读写(I/O)的解决方案:
C 语言的这套 I/O 解决方案也适用于 C++ 程序,但 C++ 并没有“偷懒”,它自己独立开发了一套全新的 I/O 解决方案,其中就包含大家一直使用的 cin 和 cout。
标准输入输出
std::cin
:标准输入流(键盘输入)。std::cout
:标准输出流(控制台输出)。std::cerr
:标准错误流(无缓冲)。std::clog
:标准日志流(有缓冲)。ios 是所有流类的基类,它派生出 istream 和 ostream。
特别需要指出的是,为了避免多继承的二义性,从 ios 派生出 istream 和 ostream 时,均使用了 virtual 关键字(虚继承)。
这些流类各自的功能分别为:
C++ 的 I/O 流基于流类库,主要包含以下类:
std::istream
:输入流基类。常用于接收从键盘输入的数据;std::ostream
:输出流基类。常用于将数据输出到屏幕上;std::iostream
:输入输出流基类。继承自 istream 和 ostream 类,因为该类的功能兼两者于一身,既能用于输入,也能用于输出;std::ifstream
:文件输入流。用于读取文件中的数据;std::ofstream
:文件输出流。用于向文件中写入数据;std::fstream
:文件输入输出流。兼 ifstream 和 ofstream 类功能于一身,既能读取文件中的数据,又能向文件中写入数据。分别对应于标准输入流、标准输出流。
声明对执行标准化 I/O 有用的服务。
为用户控制的文件处理声明服务。
在C++中,cout是标准输出流对象,用于向控制台或终端输出数据。它是iostream库中的一部分,可以通过包含头文件来使用。
使用cout进行输出非常简单,只需使用<<运算符将要输出的数据插入到cout对象中即可。以下是一些示例用法:
#include <iostream>
int main() {
int number = 42;
double pi = 3.14159;
std::string message = "Hello, world!";
std::cout << "This is a number: " << number << std::endl;
std::cout << "This is pi: " << pi << std::endl;
std::cout << "This is a message: " << message << std::endl;
return 0;
}
cout对象可以与各种数据类型一起使用,包括基本数据类型(如整数、浮点数、字符等)和自定义类型(如字符串、数组、对象等)。
需要注意的是,cout是一个全局对象,属于std命名空间。因此,在使用cout之前,我们需要使用std::前缀来指定命名空间,或者使用using namespace std;语句来引入整个std命名空间。
在C++中,cin是标准输入流对象,用于从控制台或终端读取用户输入的数据。它也是iostream库的一部分,可以通过包含头文件来使用。
使用cin进行输入非常简单,只需使用>>运算符将输入的数据存储到相应的变量中。以下是一些示例用法:
#include <iostream>
int main() {
int number;
double pi;
std::string message;
std::cout << "Enter a number: ";
std::cin >> number;
std::cout << "Enter the value of pi: ";
std::cin >> pi;
std::cout << "Enter a message: ";
std::cin.ignore(); // 忽略之前的换行符
std::getline(std::cin, message);
std::cout << "You entered: " << number << ", " << pi << ", " << message << std::endl;
return 0;
}
使用cin对象从用户那里读取了一个整数、一个浮点数和一行字符串。每个输入都使用>>运算符将输入的数据存储到相应的变量中。std::getline函数用于读取一行字符串,而std::cin.ignore()函数用于忽略之前的换行符。
cerr是标准错误流对象,用于向控制台或终端输出错误信息。它也是iostream库的一部分,可以通过包含头文件来使用。
使用cerr进行输出也非常简单,只需使用<<运算符将要输出的错误信息插入到cerr对象中即可。以下是一个示例用法:
#include <iostream>
int main() {
int dividend = 10;
int divisor = 0;
if (divisor == 0) {
std::cerr << "Error: Division by zero!" << std::endl;
} else {
int result = dividend / divisor;
std::cout << "Result: " << result << std::endl;
}
return 0;
}
进行了一个除法运算,但是当除数为零时,会输出一个错误信息到cerr对象中。这样可以将错误信息与正常输出分开,使其更易于识别和处理。
与cout不同的是,cerr对象的输出通常会直接显示在控制台或终端的错误输出流中,而不会被重定向或缓冲。这使得cerr适用于输出紧急或重要的错误信息,以便及时通知用户。
clog是标准日志流对象,用于向控制台或终端输出日志信息。它也是iostream库的一部分,可以通过包含头文件来使用。
#include <iostream>
int main() {
int value = 42;
std::clog << "This is a log message: " << value << std::endl;
return 0;
}
使用clog对象输出了一个日志信息,其中包含一个整数值。与cout和cerr不同,clog对象的输出通常会被缓冲,这意味着日志信息可能不会立即显示在控制台或终端上,而是在适当的时机进行刷新。
clog对象通常用于输出一般的日志信息,既不像cout那样用于正常输出,也不像cerr那样用于错误信息。它可以用于记录程序的运行状态、调试信息或其他重要的日志记录。
内存中存放的数据在计算机关机后就会消失。要长久保存数据,就要使用硬盘、光盘、U 盘等设备。为了便于数据的管理和检索,引入了“文件”的概念。
成千上万个文件如果不加分类放在一起,用户使用起来显然非常不便,因此又引入了树形目录(目录也叫文件夹)的机制,可以把文件放在不同的文件夹中,文件夹中还可以嵌套文件夹,这就便于用户对文件进行管理和使用。
所谓“格式”,就是关于文件中每一部分的内容代表什么含义的一种约定。 例如,常见的纯文本文件(也叫文本文件,扩展名通常是“.txt”),指的是能够在 Windows 的“记事本”程序中打开,并且能看出是一段有意义的文字的文件。文本文件的格式可以用一句话来描述:文件中的每个字节都是一个可见字符的 ASCII 码。
所谓“文本文件”和“二进制文件”,只是约定俗成的、从计算机用户角度出发进行的分类,并不是计算机科学的分类。因为从计算机科学的角度来看,所有的文件都是由二进制位组成的,都是二进制文件。文本文件和其他二进制文件只是格式不同而已。
程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放。
通过文件可以将数据持久化
C++中对文件操作需要包含头文件 ==< fstream >==
文件类型分为两种:
C++ 标准库中还专门提供了 3 个类用于实现文件操作,它们统称为文件流类,这 3 个类分别为:
写文件步骤如下:
文件打开方式可以配合使用,利用|操作符。文件打开方式:
打开方式 | 解释 |
---|---|
ios::in | 为读文件而打开文件 |
ios::out | 为写文件而打开文件 |
ios::ate | 初始位置:文件尾 |
ios::app | 追加方式写文件 |
ios::trunc | 如果文件存在先删除,再创建 |
ios::binary | 二进制方式 |
例如: 用二进制方式写文件 ios::binary | ios:: out
#include <fstream>
void test1() {
ofstream ofs;
ofs.open("2_4.txt" ,ios::out);
ofs << "姓名:张三" << endl;
ofs << "性别:男" << endl;
ofs << "年龄:18" << endl;
ofs.close();
}
int main() {
test1();
return 0;
}
总结:
读文件与写文件步骤相似,但是读取方式相对于比较多。读文件步骤如下:
示例:
#include "fstream"
#include "string"
#include "iostream"
using namespace std;
void test() {
ifstream ifs;
ifs.open("text.txt", ios::in);
if (!ifs.is_open()) {
cout << "文件打开失败" << endl;
return;
}
//第一种方式
char buf[1024] = {0};
while (ifs >> buf) {
cout << buf << endl;
}
//第二种
// char buf[1024] = {0};
// while (ifs.getline(buf, sizeof(buf))) {
// cout << buf << endl;
// }
//第三种
// string buf;
// while (getline(ifs, buf)) {
// cout << buf << endl;
// }
// char c;
// while ((c = ifs.get()) != EOF) {
// cout << c;
// }
ifs.close();
}
int main() {
test();
return 0;
}
总结:
fstream 是 C++ 标准库中用于文件输入输出的类,它结合了 ifstream(输入文件流)和 ofstream(输出文件流)的功能,既可以读取文件,也可以写入文件。
#include <iostream>
#include <fstream>
#include <string>
int main() {
std::fstream file("example.txt", std::ios::in | std::ios::out | std::ios::app);
if (!file.is_open()) {
std::cerr << "Failed to open file!" << std::endl;
return 1;
}
// 写入数据
file << "Appending a new line to the file." << std::endl;
// 将文件指针移动到文件开头
file.seekg(0, std::ios::beg);
// 读取文件内容
std::string line;
while (std::getline(file, line)) {
std::cout << line << std::endl;
}
file.close();
return 0;
}
以二进制的方式对文件进行读写操作。打开方式要指定为 ==ios::binary==
二进制方式写文件主要利用流对象调用成员函数write
函数原型 :ostream& write(const char * buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数
#include "fstream"
#include "string"
using namespace std;
class Person {
public:
char name[64];
int age;
};
void test() {
//1、包含头文件
//2、创建输出流对象
ofstream ofs("person.txt", ios::out | ios::binary);
//3、打开文件
//ofs.open("person.txt", ios::out | ios::binary);
Person p = {"张三" , 18};
//4、写文件
ofs.write((const char *)&p, sizeof(p));
//5、关闭文件
ofs.close();
}
int main() {
test();
return 0;
}
总结: 文件输出流对象 可以通过write函数,以二进制方式写数据
二进制方式读文件主要利用流对象调用成员函数read
函数原型:istream& read(char *buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数
示例:
#include "fstream"
#include "string"
#include "iostream"
using namespace std;
class Person {
public:
char name[64];
int age;
};
void test() {
//2、创建输入流对象
ifstream ifs("person.txt", ios::in | ios::binary);
if (!ifs.is_open()) {
cout << "文件打开失败" << endl;
return;
}
//3、打开文件
//ofs.open("person.txt", ios::in | ios::binary);
Person p;
//4、读文件
ifs.read((char *)&p, sizeof(p));
//5、关闭文件
ifs.close();
cout << "姓名: " << p.name << " 年龄: " << p.age << endl;
}
int main() {
test();
return 0;
}
文件输入流对象 可以通过read函数,以二进制方式读数据
std::fstream类中定义了一些成员函数和状态标志,用于检测和处理文件错误和状态。以下是一些常用的状态标志和相关的成员函数:
fail():检测文件操作是否失败。返回true表示失败,返回false表示成功。 bad():检测文件流是否处于错误状态。返回true表示错误,返回false表示正常。 eof():检测文件流是否到达文件末尾。返回true表示到达末尾,返回false表示未到达末尾。 good():检测文件流是否处于正常状态。返回true表示正常,返回false表示出现错误。 clear():清除文件流的错误状态标志。 rdstate():返回当前文件流的状态标志。 setstate():设置文件流的状态标志。
通过使用这些成员函数和状态标志,可以检测和处理文件操作中的错误和状态。例如,可以使用fail()函数来检测文件读取操作是否失败,然后使用clear()函数来清除错误状态标志。
void test() {
cout << "文件错误与状态" << endl;
std::ifstream file("example.txt");
//std::ifstream file("yc.txt");
if (!file) {
//我们检测文件是否成功打开,如果打开失败,则输出错误信息并返回。
std::cerr << "Failed to open the file." << std::endl;
return;
}
int num;
//然后,我们使用while循环从文件中读取整数,并检测读取操作是否失败。如果失败,则输出错误信息并清除错误状态标志。
while (file >> num) {
if (file.fail()) {
std::cerr << "Error reading the file." << std::endl;
file.clear(); // 清除错误状态标志
break;
}
std::cout << num << " ";
}
if (file.eof()) {
//最后,我们检测是否到达文件末尾,并关闭文件。
std::cout << std::endl << "End of file reached." << std::endl;
}
file.close();
std::cerr << "file to close" << std::endl;
//在上述示例中,我们打开了一个名为example.txt的文件,并使用std::ifstream对象file进行读取操作。
}
int main() {
test();
return 0;
}
在C++中,可以使用文件流对象的std::ofstream类来实现文件的追加操作。可以创建新文件或打开已存在的文件进行写入。
要实现文件的追加,需要在打开文件时指定追加模式。可以使用std::ios::app标志来指定追加模式,它会将数据追加到文件的末尾而不是覆盖原有内容。
void test() {
cout << "文件的追加" << endl;
std::ofstream file("yc.txt" , std::ios::app);
if (!file) {
std::cerr << "Failed to open the file." << std::endl;
return;
}
file << "This is a new line." << std::endl;
file << "This is another line." << std::endl;
file.close();
std::ifstream inFile("yc.txt" , std::ios::binary | std::ios::in);
if (inFile.is_open()) {
int data[5];
inFile.read(reinterpret_cast<char*>(data), sizeof(data));
for (int i = 0; i < 5; i++) {
std::cout << data[i] << " " <<endl;
}
inFile.close();
std::cout << std::endl << "Binary file read successfully." << std::endl;
} else {
std::cout << "Failed to open the file for reading." << std::endl;
}
}
int main() {
test();
return 0;
}
在C++中,可以使用文件流对象的eof()函数来判断文件是否已经到达结尾。eof()函数是std::istream和std::ostream类的成员函数,用于检测文件流是否已经到达文件末尾。
eof()函数返回一个bool值,如果文件流已经到达文件末尾,则返回true,否则返回false。
以下是一个示例,演示了如何使用eof()函数来判断文件是否已经到达结尾:
void test() {
cout << "文件结尾的判断" << endl;
std::ifstream file("yc.txt");
if (!file) {
//首先,我们检测文件是否成功打开,如果打开失败,则输出错误信息并返回。
std::cerr << "Failed to open the file." << std::endl;
return;
}
std::string line;
//使用std::getline()函数从文件中逐行读取数据,并将每行数据输出到控制台。
while (std::getline(file,line)) {
std::cout << line << std::endl;
}
if (file.eof()) {
//使用eof()函数检测文件是否已经到达结尾。如果到达结尾,则输出相应的提示信息。
std::cout << "End of file reached." << std::endl;
}
file.close();
}
int main() {
test();
return 0;
}
在C++中,可以使用文件流对象的seekg()和seekp()函数来在指定位置进行文件的读取和写入操作。这两个函数用于设置文件流的读取和写入位置。
seekg()函数用于设置输入文件流的读取位置,而seekp()函数用于设置输出文件流的写入位置。这两个函数都接受一个参数,表示要设置的位置。
以下是一个示例,演示了如何在指定位置读取和写入文件:
void test() {
cout << "在指定位置读/写文件" << endl;
std::fstream file("yc.txt",std::ios::in | std::ios::out);
if (!file) {
std::cerr << "Failed to open the file." << std::endl;
}
cout << "修改前的文件内容" << endl;
string buf;
while (getline(file, buf)) {
cout << buf << endl;
}
// 在指定位置读取文件
file.seekg(5, std::ios::beg); // 从文件开头偏移5个字节
char ch;
file >> ch;
std::cout << "Character at position 5: " << ch << std::endl;
// 在指定位置写入文件
file.seekp(10, std::ios::beg); // 从文件开头偏移10个字节
file << "XYZ";
file.close();
}
int main() {
test();
return 0;
}
文件操作时,需要检查文件是否成功打开或读取。
#include <iostream>
#include <fstream>
int main() {
std::ifstream inFile("nonexistent.txt");
if (!inFile) {
std::cerr << "Failed to open file!n";
return 1;
}
return 0;
}
可以通过 exceptions()
方法启用文件流的异常处理。
#include <iostream>
#include <fstream>
int main() {
std::ifstream inFile;
inFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
inFile.open("nonexistent.txt");
} catch (const std::ifstream::failure &e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
return 0;
}
从控制面板输入信息,把这些内容写到指定的文本文件。第一步:获取键盘输入内容;第二步:将内容写入到对应文本文件。
int main() {
ofstream ofs;
ofs.open("yc.txt",ios::out);
//第一步,从键盘获取数据
//string data;
char data[64];
cout << "Writing to the file" << endl;
cout << "Enter your name: ";
//键盘输入数据
cin.getline(data, 100);
ofs << data << endl;
cout << "Enter your age: ";
cin >> data;
cin.ignore();
// 再次向文件写入用户输入的数据
ofs << data << endl;
cout << "Enter your book: ";
cin >> data;
cin.ignore();
ofs << data << endl;
ofs.close();
return 0;
}
需求:读取一个文件的内容,然后复制到另一个文件中。
void test() {
//使用std::ifstream类打开源文件,并使用std::ofstream类创建目标文件。
//我们使用std::ios::binary标志来以二进制模式打开文件,以确保正确复制文件的内容。
std::ifstream source_file("yc.txt",std::ios::binary);
std::ofstream destination_file("ycdoubi.txt",std::ios::binary);
if (!source_file) {
std::cout << "无法打开源文件" << std::endl;
return;
}
if (!destination_file) {
std::cout << "无法创建目标文件" << std::endl;
return;
}
char ch;
//使用get函数从源文件逐个字节读取内容,并使用put函数将字节写入目标文件,从而实现文件的复制。这个过程会一直进行,直到源文件的末尾。
while (source_file.get(ch)) {
destination_file.put(ch);
}
//请注意,这个示例是逐个字节复制文件的简单实现。对于大型文件,逐个字节的复制可能效率较低。
//在实际应用中,您可以使用更高效的方法,如缓冲区复制或使用std::copy函数。
source_file.close();
destination_file.close();
std::cout << "文件复制完成" << std::endl;
}
int main() {
test();
return 0;
}