IO流
- 一、C语言的输入与输出
- 1、介绍
- 2、输入输出缓冲区
- (1)介绍
- (2)示意图
- 二、流
- 1、介绍
- 2、主要特点
- 三、C++IO流
- 1、介绍
- 2、示意图
- 四、iostream
- 1、介绍
- 2、基本概念
- 3、注意
- 五、类型转换
- 1、operator bool
- (1)介绍
- (2)示例
- (3)示例代码1
- 2、构造函数
- 3、C++类型转换
- 六、文件IO流(fstream)
- 1、介绍
- 2、示例
- 3、参数mode
- 4、二进制方式读写
- (1)示例代码
- (2)运行结果
- (3)注意
- 5、文本方式读写
- (1)示例代码
- (2)运行结果
- 七、stringstream
- 1、介绍
- 2、主要特点
- 3、示例代码
- 4、运行结果
- 5、注意
一、C语言的输入与输出
1、介绍
- C语言中的输入与输出(I/O)流主要通过标准库中的几个函数来实现,这些函数允许程序从外部设备(如键盘、文件等)读取数据,并将数据输出到外部设备(如显示器、文件等)。
- C语言的这些输入与输出操作都借助了相应的缓冲区。
2、输入输出缓冲区
(1)介绍
- C语言的输入输出缓冲区是处理输入输出操作的一个重要概念。它位于用户程序与操作系统之间,用于暂存输入输出数据,以减少直接对物理设备的读写次数,从而提高程序的运行效率。
(2)示意图
二、流
1、介绍
- 在编程中,流(Streams)是一个抽象的概念,用于表示数据的有序集合,这些数据可以是输入到程序中的,也可以是程序生成的输出。
- 流提供了一种连续访问数据的机制,而不需要一次性将整个数据集加载到内存中。这种方式特别适用于处理大量数据或需要实时处理数据的情况。
2、主要特点
- 顺序性:流中的数据项是按顺序排列的,通常只能按顺序访问。
- 单向性:流是单向的,即数据只能从一个方向流动。
- 抽象性:流是对数据源的抽象,它隐藏了数据的实际来源或目的地。程序通过流接口与数据源进行交互,而不需要关心数据的具体存储方式或位置。
- 灵活性:流支持多种数据类型和编码方式,可以轻松地处理文本、二进制数据、图像等多种类型的数据。
- 缓冲:为了提高性能,流通常使用缓冲区来暂存数据。数据可以分批从数据源读取到缓冲区中,然后再从缓冲区中读取到程序中,或者相反,数据可以先写入缓冲区,然后再批量写入到目标中。
三、C++IO流
1、介绍
- C++系统实现了一个庞大的类库,其中ios为基类,其他类都是直接或间接派生自ios类。
2、示意图
四、iostream
1、介绍
- 在C++中,iostream是一个非常重要的库,它提供了用于输入输出的功能。
- iostream库中的类,特别是istream、ostream和iostream(以及它们的派生类,如cin、cout、ifstream、ofstream和fstream),是C++标准库的一部分,用于处理字符数据的输入和输出。
2、基本概念
- cin:一个istream类的对象,用于从标准输入(通常是键盘)读取数据。
- cout:一个ostream类的对象,用于向标准输出(通常是屏幕)写入数据。
- cerr和clog:两个都是ostream类的对象,分别用于错误消息和日志消息的输出。它们与cout的主要区别在于,cerr是不经过缓冲的(即立即输出),而clog是缓冲的,并且默认与cout共享同一个缓冲区,但可以通过 clog.sync_with_stdio(false); 来取消这种共享。
3、注意
- cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,则会留在那儿慢慢用。而如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完后,才要求输入新的数据。
- 输入的数据类型必须与要提取的数据类型一致,否则出错。出错只是在流的状态字state中对应位置位(置1),程序依然继续执行。
- 空格和回车都可以作为数据之间的分格符,所以多个数据可以在一行输入,也可以分行输入。但如果是字符型和字符串,则空格(ASCII码为32)无法用cin输入,字符串中也不能有空格,回车符也无法读入。除非使用getline函数。
- cin和cout可以直接输入和输出内置类型数据,因为标准库已经将所有内置类型的输入和输出全部重载了。
- 对于自定义类型,如果要支持cin和cout的标准输入输出,需要对 << 和 >> 进行重载。
五、类型转换
1、operator bool
(1)介绍
- 在C++中,operator bool() 是一个类型转换操作符(也称为转换函数或转换操作符),它允许你的类对象在需要布尔值时被隐式或显式地转换成布尔类型(bool)。
- 这种转换常用于控制流语句(如if语句、while循环等)中,以及任何期望布尔表达式的上下文中。
- 当定义operator bool()时,通常会让它在对象处于某种有效或非空状态时返回true,在其他情况下返回false。
- 这个操作符应该被声明为const,因为它不应该修改对象的状态。
(2)示例
(3)示例代码1
class TestOpBl
{
public:
operator bool()
{
return _isValid;
}
private:
bool _isValid = true;
};
int main()
{
TestOpBl ob;
if (ob)
cout << "test true" << endl;
return 0;
}
2、构造函数
class A
{
public:
A(int x)
{}
};
class B
{
public:
B(const A& a)
{}
};
class C
{
public:
operator int()
{
return 0;
}
};
int main()
{
A a = 1;
B b = a;
C c;
int x = c;
return 0;
}
3、C++类型转换
- 参见类型转换与RTTI。
六、文件IO流(fstream)
1、介绍
- C++中的文件IO(输入输出)流是通过C++标准库中的< fstream >头文件提供的。这个头文件包含了用于文件操作的类,如ifstream(用于从文件读取)、ofstream(用于向文件写入)和fstream(既可以读取也可以写入文件)。
- 这些类都是基于C++的IO流库构建的,它们继承自istream和ostream类,因此可以使用与标准输入输出(cin和cout)相同的操作符和方法。
2、示例
3、参数mode
- mode是描述文件请求的I/O模式的标志。它是位掩码成员类型openmode的对象,由以下成员常量的组合组成。
- in:即input,文件打开读取,内部流缓冲区支持输入操作。
- out:即output,文件打开写入,内部流缓冲区支持输出操作。
- binary:操作以二进制模式而不是文本模式执行。
- ate:即at end,输出位置从文件末尾开始。
- app:即append,所有输出操作都发生在文件末尾,附加到其现有内容中。
- trunc:即truncate,文件打开前存在的任何内容都将被丢弃。
- 这些标志可以与位或运算符(|)组合使用,即使用多种。
4、二进制方式读写
(1)示例代码
struct ServerInfo
{
char _name[64];
char _address[128];
int _id;
Date _d;
};
class BinaryIo
{
public:
BinaryIo(const char* name = "binaryio.bin")
:_name(name)
{}
void WriteInfo(const ServerInfo& info)
{
ofstream ofs(_name, ios_base::out | ios_base::binary);
ofs.write((char*)&info, sizeof(info));
}
void ReadInfo(ServerInfo& info)
{
ifstream ifs(_name, ios_base::in | ios_base::binary);
ifs.read((char*)&info, sizeof(info));
}
private:
string _name;
};
void TestBinaryIoWrite()
{
BinaryIo bio;
ServerInfo sif = { (char*)"snowdragon", "https://legacy.cplusplus.com/reference/fstream/ifstream/ifstream/", 123456, {2024,8,14}};
bio.WriteInfo(sif);
}
void TestBinaryIoRead()
{
BinaryIo bio;
ServerInfo sif;
bio.ReadInfo(sif);
cout << sif._name << endl;
cout << sif._address << endl;
cout << sif._id << endl;
cout << sif._d << endl;
}
void TestBinaryIo()
{
//TestBinaryIoWrite();
TestBinaryIoRead();
}
(2)运行结果
(3)注意
- ServerInfo类中的成员不能用指针,否则输出到文件中时,内容只是指针指向的地址。如果写入和获取使用数据的程序不在同一作用域中,则指针类型的成员指向的对象会进行析构,而要取出对应数据时,就是越界访问。
- 容器也不行,例如string容器,其中是由指针指向地址的方式维护的,输出时也是指针指向的地址而不是内容。
5、文本方式读写
(1)示例代码
class TextIo
{
public:
TextIo(const char* name = "textio.txt")
:_name(name)
{}
void WriteInfo(const ServerInfo& info)
{
ofstream ofs(_name, ios_base::out);
ofs << info._name << endl;
ofs << info._address << endl;
ofs << info._id << endl;
ofs << info._d << endl;
}
void ReadInfo(ServerInfo& info)
{
ifstream ifs(_name, ios_base::in);
ifs >> info._name;
ifs >> info._address;
ifs >> info._id;
ifs >> info._d;
}
private:
string _name;
};
void TestTextIoWrite()
{
TextIo tio;
ServerInfo sif = { (char*)"snowdragon", "https://legacy.cplusplus.com/reference/fstream/ifstream/ifstream/", 123456, {2024,8,14} };
tio.WriteInfo(sif);
}
void TestTextIoRead()
{
TextIo tio;
ServerInfo sif;
tio.ReadInfo(sif);
cout << sif._name << endl;
cout << sif._address << endl;
cout << sif._id << endl;
cout << sif._d << endl;
}
void TestTextIo()
{
//TestTextIoWrite();
TestTextIoRead();
}
(2)运行结果
七、stringstream
1、介绍
- stringstream是一种内存中的输入输出流(I/O stream),它允许使用者像操作文件流(如ifstream和ofstream)那样,在内存中读写字符串。这使得stringstream成为处理字符串数据时的强大工具,尤其是在需要格式化字符串、解析字符串或进行复杂的数据转换时。
2、主要特点
- 内存中的字符串流:stringstream在内存中操作,不直接与文件或其他外部设备交互。
- 输入/输出功能:它既可以作为输入流(使用>>操作符)读取数据,也可以作为输出流(使用<<操作符)写入数据。
- 灵活的数据处理:可以轻松地在各种数据类型之间转换,包括基本数据类型(如int、float和double等)和字符串。
3、示例代码
struct ChatInfo
{
string _name;
string _id;
Date _d;
string _msg;
};
void test_stringstream()
{
stringstream oss;
ChatInfo wci = { "snowdragon", "123456", {2024,8,15}, "writed by snowdragon" };
oss << wci._name << endl;
oss << wci._id << endl;
oss << wci._d << endl;
oss << wci._msg << endl;
//可进行传输操作
ChatInfo rci;
stringstream iss(oss.str());
iss >> rci._name;
iss >> rci._id;
iss >> rci._d;
iss.ignore();
getline(iss, rci._msg);
cout << "-------------------------------------------------------" << endl;
cout << "姓名:" << rci._name << "(" << rci._id << ") ";
cout << rci._d << endl;
cout << rci._name << ":>" << rci._msg << endl;
cout << "-------------------------------------------------------" << endl;
}
int main()
{
test_stringstream();
return 0;
}
4、运行结果
5、注意
- 上方代码中的ignore函数需要加上,否则该处下方的getline函数只是获取换行符 \n。上一个 >> 操作只是识别到换行符就结束,而不会跳过换行符。最终getline获取到 \n,并把 \n转化为了\0给rci._msg。
- stringstream实际是在其底层维护了一个string类型的对象用来保存结果。
- 多次数据类型转化时,一定要用clear()来清空,才能正确转化,但clear()不会将stringstream底层的string对象清空。
- 可以使用s. str(“”)方法将底层string对象设置为空字符串。使用s.str()让stringstream返回其底层的string对象。
- stringstream使用string类对象代替字符数组,可以避免缓冲区溢出的危险,而且其会对参数类型进行推演,不需要格式化控制,也不会出现格式化失败的风险,因此使用更方便,也更安全。
本文到这里就结束了,如有错误或者不清楚的地方欢迎评论或者私信
创作不易,如果觉得博主写得不错,请点赞、收藏加关注支持一下💕💕💕