【C++】文件处理(IO流)

文章目录

  • C++ IO流
    • 1. C语言IO
    • 2. C++IO
      • 2.1 C++标准IO流
      • 2.2 C++文件IO流
      • 2.3 C++ IO 文件常用函数总结表
      • 2.4 C++ stringstream


C++ IO流

回顾一下,C语言中IO输入输出的

1. C语言IO

C语言中常用的输入输出函数有如下几种:前者是格式化标准输入输出,后者是格式化文件输入输出,最后是格式化字符串输入输出。

函数名内容
scanf从标准输入流(键盘)读取格式化的数据
fscanf从所有输入流读取读取格式化数据
sscanf从字符串中读取格式化的数据
printf将格式化的数据输出到标准输出流(屏幕)上
fprintf将格式化数据输出到所有输出流上
sprintf将格式化的数据输出到字符串中

文件的输入输出需要以下几个函数:

函数名功能
fopen打开文件流
fclose关闭文件流
fscanf从所有输入流读取读取格式化数据
fprintf将格式化数据输出到所有输出流上
fread二进制输入
fwrite二进制输出
//文件开关
FILE* fopen   (const char* filename, const char* mode);
int   fclose  (FILE* stream);
//格式化读写
int fprintf (FILE* stream, const char* format [, argument ]...);
int fscanf  (FILE* stream, const char* format [, argument ]...);
//二进制读写
size_t fwrite  (const void* buffer, size_t size, size_t count, FILE* stream);
size_t fread   (      void* buffer, size_t size, size_t count, FILE* stream);

使用方式如下:

struct ServerInfo 
{
	char _ip[32];
	int _port;
	friend ostream& operator<<(ostream& os, ServerInfo& info);
	friend ostream& operator>>(ostream& os, ServerInfo& info);
};
//测试C语言二进制读写
void TestC_Write_Bin() {
	ServerInfo info = { "192.168.1.1",80 };
	FILE* fout = fopen("info.bin", "wb");
    //assert();
	fwrite(&info, sizeof(ServerInfo), 1, fout);
	fclose(fout);
}
void TestC_Read_Bin() {
	ServerInfo info;
	FILE* fin = fopen("info.bin", "rb");
	fread(&info, sizeof(ServerInfo), 1, fin);
	printf("%s:%d", info._ip, info._port);
	fclose(fin);
}
//测试C语言字符读写
void TestC_Write_Text() {
	ServerInfo info = { "192.168.1.1",80 };
	FILE* fout = fopen("info.txt", "w");
	fprintf(fout, "%s %d", info._ip, info._port);
	fclose(fout);
}
void TestC_Read_Text() {
	ServerInfo info;
	FILE* fin = fopen("info.txt", "r");
	fscanf(fin, "%s %d", &info._ip, &info._port);
	printf("%s:%d", info._ip, info._port);
}

 

2. C++IO

C++ 标准库提供了4个全局流对象cincoutcerrclog。cout、cerr、clog 是 ostream 类的三个不同的对象。使用 cout 进行标准输出,使用 cin 进行标准输入。同时 C++ 标准库还提供了 cerr 用来进行标准错误的输出,以及 clog 进行日志的输出。

以下是常用的标准输入输出对象:

  • cin:标准输入流对象。
  • cout:标准输出流对象。
  • cerr:标准错误输出流对象,通常用于输出错误信息。
  • clog:标准日志流对象,用于输出日志信息。

2.1 C++标准IO流

cout,cinostream,istream类的对象,operator<<,operator>>分别是两个对象的操作符重载成员函数。

C++输出输入可直接使用cout>>cin>>,因为其重载了所有内置类型,对于自定义类型需要自行重载操作符>><<

cin >> a >> b;

operator<<operator>>的返回值也是ostream&istream&,因此支持连续输入输出,又是一次函数调用。

cout/cin 取代 printf/scanf 的真正原因是 cout/cin 支持自定义类型,符合面向对象的思想。

当需要循环读入数据时,可以采用如下的方式:

string str;
while (cin >> str) {
	;
}

从文档中可以看到,operator>>的返回值是istream类型,这个对象类型是如何作真假判断的呢?

原因是istream类的对象支持一个操作符的重载函数叫operator bool,C++98中叫operator void*,C++11中叫operator bool

这是个特殊的运算符重载函数,该函数不允许限定返回类型,当类型被当作条件判断时,自动调用并将返回值强转为内置的标识,该标识如果为真就继续,如果为假就停止读取。

2.2 C++文件IO流

采用面向对象的思想,C++中文件指针被文件输入输出流对象ofstreamifstream代替。

fopen的调用方式类似,创建输入输出流对象,调用其构造函数传入文件地址以及打开模式。fclose被析构函数代替,且析构函数可以自动调用。
 

主要的两个IO类

对象构造函数解释
ofstream (const char fileName, ios_base::openmode mode=ios_base::out)*创建输出流对象,并指定文件地址和打开模式
ifstream (const char fileName, ios_base::openmode mode=ios_base::in)*创建输入流对象,并指定文件地址

ofstream-写文件:

//1. 按字符写入文件内容
void writeCharByChar(const std::string& fileName, const std::string& content) {
    std::ofstream ofs(fileName);
    if (!ofs) {
        std::cerr << "无法打开文件进行写入!" << std::endl;
        return;
    }

    for (char c : content) {
        ofs.put(c);
    }
    ofs.close();
}

//2. 使用 put() 方法写入文件内容
void writeUsingPut(const std::string& fileName, const std::string& content) {
    std::ofstream ofs(fileName);
    if (!ofs) {
        std::cerr << "无法打开文件进行写入!" << std::endl;
        return;
    }

    for (char c : content) {
        ofs.put(c);
    }
    ofs.close();
}

//3. 按行写入文件内容
void writeLineByLine(const std::string& fileName, const std::string& content) {
    std::ofstream ofs(fileName);
    if (!ofs) {
        std::cerr << "无法打开文件进行写入!" << std::endl;
        return;
    }

    ofs << content << std::endl;
    ofs.close();
}

//4. 使用 write() 方法写入文件内容
void writeUsingWrite(const std::string& fileName, const std::string& content) {
    std::ofstream ofs(fileName, std::ios::binary);
    if (!ofs) {
        std::cerr << "无法打开文件进行写入!" << std::endl;
        return;
    }

    ofs.write(content.c_str(), content.size());
    ofs.close();
}

 

当然,请看下面的表格,它列出了C++中常用的文件打开模式及其解释:

模式解释
ios::in输入模式,用于读取文件。
ios::out输出模式,用于写入文件。
ios::binary二进制模式,用于以二进制方式读写文件。
ios::ate在文件末尾打开文件,初始位置为文件末尾。
ios::app追加模式,用于在文件末尾追加内容而不覆盖已有内容。
ios::trunc如果文件已存在,则清空文件内容。
ios::in | ios::binary同时指定输入模式和二进制模式,用于以二进制方式读取文件。
ios::out | ios::binary同时指定输出模式和二进制模式,用于以二进制方式写入文件。

常用的有如上几种,该变量的值以二进制位中的不同位为1来标识,也就是说使用异或|就可以组合起来用。

ifstream-读取文件

// 1.按字符读取文件内容
void readCharByChar(const std::string& fileName) {
    std::ifstream ifs(fileName);
    if (!ifs) {
        std::cerr << "无法打开文件进行读取!" << std::endl;
        return;
    }

    char c;
    // 逐个字符读取文件内容并输出
    while (ifs.get(c)) {
        std::cout << c;
    }
    ifs.close();
}

// 2.使用 get() 方法读取文件内容
void readUsingGet(const std::string& fileName) {
    std::ifstream ifs(fileName);
    if (!ifs) {
        std::cerr << "无法打开文件进行读取!" << std::endl;
        return;
    }

    char buffer[128];
    // 逐块读取文件内容并输出,每次读取最多128个字符
    while (ifs.get(buffer, sizeof(buffer))) {
        std::cout << buffer;
    }
    ifs.close();
}

// 3.按行读取文件内容
void readLineByLine(const std::string& fileName) {
    std::ifstream ifs(fileName);
    if (!ifs) {
        std::cerr << "无法打开文件进行读取!" << std::endl;
        return;
    }

    std::string line;
    // 逐行读取文件内容并输出
    while (std::getline(ifs, line)) {
        std::cout << line << std::endl;
    }
    ifs.close();
}

// 4.使用 read() 方法读取文件内容
void readUsingRead(const std::string& fileName) {
    std::ifstream ifs(fileName, std::ios::binary);
    if (!ifs) {
        std::cerr << "无法打开文件进行读取!" << std::endl;
        return;
    }

    // 移动到文件末尾
    ifs.seekg(0, std::ios::end);
    // 获取文件大小
    std::streampos fileSize = ifs.tellg();
    // 移动回文件开头
    ifs.seekg(0, std::ios::beg);

    char buffer[128];
    // 逐块读取文件内容并输出,每次读取最多128个字符
    while (ifs.read(buffer, sizeof(buffer))) {
        std::cout.write(buffer, ifs.gcount());
    }

    // 处理剩余的字符
    ifs.read(buffer, sizeof(buffer));
    std::cout.write(buffer, ifs.gcount());

    ifs.close();
}

 

函数:

函数解释
istream& read(char s, streamsize n);*read接口是输入流istream对象的成员函数,参数是变量和大小。
ostream& write(const char s , streamsize n);*write接口是输出流ostream对象的成员函数,参数是写入变量和写入大小。

示例

使用一个ConfigManage类来演示几种文件读写的方式。

struct ServerInfo 
{
	char _ip[32];
	int _port;
	friend ostream& operator<<(ostream& os, ServerInfo& info);
	friend ostream& operator>>(ostream& os, ServerInfo& info);
};
class ConfigManage {
public:
	ConfigManage(const char* fileName)
		:_fileName(fileName)
	{}
    //二进制写入
	void WriteBin(ServerInfo& info)
	{
		ofstream ofs(_fileName.c_str(), ios_base::out | ios_base::binary); //创建输出流对象
		ofs.write((const char*)&info, sizeof(ServerInfo)); //调用write接口
	}
    //二进制读取
	void ReadBin(ServerInfo& info)
	{
		ifstream ifs(_fileName.c_str(), ios_base::in | ios_base::binary);
		ifs.read((char*)&info, sizeof(ServerInfo));
		cout << info << endl;
	}
private:
	string _fileName;
};

读写文件更常用的方式是以文本形式读写,因此就可以省略打开模式参数。

ifstream,ofstream文件输入输出类中还继承了iostream的流插入<<流提取>>操作符,也就是对象ofsifs也可以使用<<>>操作符。

struct ServerInfo {
	friend ostream& operator<<(ostream& os, ServerInfo& info);
	friend ostream& operator>>(ostream& os, ServerInfo& info);
    char _ip[32];
	int _port;
};
ostream& operator<<(ostream& os, ServerInfo& info) {
	os << info._ip << " " << info._port;
	return os;
}
istream& operator>>(istream& is, ServerInfo& info) {
	is >> info._ip >> info._port;
	return is;
}
//文本写入
void WriteText(ServerInfo& info)
{
    ofstream ofs(_fileName.c_str());
    //write
    ofs.write((const char*)&info, sizeof(ServerInfo));
    //1.
    ofs << info._ip << info._port; //对象未重载<<
	//2.
    ofs << info; //对象已重载>>
}
//文本读取
void ReadText(ServerInfo& info)
{
    ifstream ifs(_fileName.c_str());
    //read
    ifs.read((char*)&info, sizeof(ServerInfo));
	//1.
    ofs << info._ip << info._port; //对象未重载<<
	//2.
    ifs >> info; //对象已重载>>
    cout << info << endl;
}

具体调用方式则是如下:

void TestCPP_Write_Bin() {
	ServerInfo info = { "192.168.1.1",80 };
	ConfigManage con("config.bin");
	con.WriteBin(info);
}
void TestCPP_Read_Bin() {
	ServerInfo info;
	ConfigManage con("config.bin");
	con.ReadBin(info);
}
void TestCPP_Write_Text() {
	ServerInfo info = { "192.168.1.1",80 };
	ConfigManage con("config.bin");
	con.WriteText(info);
}
void TestCPP_Read_Text() {
	ServerInfo info;
	ConfigManage con("config.bin");
	con.ReadText(info);
}

文件的输入输出流对象调用构造函数时也可能会失败,C++采取面向对象抛异常的形式。

2.3 C++ IO 文件常用函数总结表

函数及操作符说明
文件位置操作
ifs.seekg(pos)设置输入位置指针到指定位置。
ofs.seekp(pos)设置输出位置指针到指定位置。
ifs.tellg()返回输入位置指针的当前位置。
ofs.tellp()返回输出位置指针的当前位置。
按字符读取和写入
ifs.get(char& ch)从输入流中读取一个字符。
ofs.put(char ch)向输出流中写入一个字符。
按行读取和写入
std::getline(ifs, std::string& str)从输入流中读取一行文本,存储到字符串中。
ofs << str向输出流中写入一个字符串。
读取和写入块数据
ifs.read(char* buffer, streamsize n)从输入流中读取n个字符到缓冲区中。
ofs.write(const char* buffer, streamsize n)将缓冲区中的n个字符写入输出流中。
流状态检查
ifs.eof()判断输入流是否到达文件末尾。
ifs.fail()判断输入流是否发生读取错误。
ifs.good()判断输入流是否处于良好状态。
ifs.clear()清除流的错误状态标志。
字符串流
std::istringstream iss创建字符串输入流。
std::ostringstream oss创建字符串输出流。
iss.str(std::string str)将字符串设置为输入流的内容。
oss.str()获取输出流的字符串内容。
流插入和提取操作符
ifs >> var从输入流中提取数据到变量。
ofs << var将变量的数据插入输出流。

2.4 C++ stringstream

在头文件 下,有三个类:istringstream、ostringstream 和 stringstream,分别用来进行字符串流的输入、输出和输入输出操作。

  • istringstream类用于从字符串中提取数据,类似于从文件或标准输入流中读取数据。它可以将字符串内容转换为各种数据类型。

  • ostringstream类用于将数据写入字符串,类似于将数据写入文件或标准输出流。它可以将各种数据类型转换为字符串。

  • stringstream 类同时支持字符串输入和输出操作。它可以在同一个对象中进行数据的读取和写入。

    在这里插入图片描述

下面的示例代码展示了如何使用 ostringstreamistringstream 对自定义对象进行序列化和反序列化

struct PersonInfo {
    std::string _name;
    int _age;

    friend std::ostream& operator<<(std::ostream& os, const PersonInfo& info) {
        os << info._name << " " << info._age;
        return os;
    }

    friend std::istream& operator>>(std::istream& is, PersonInfo& info) {
        is >> info._name >> info._age;
        return is;
    }
};

int main() {
    // 序列化
    PersonInfo info1 = { "zhangsan", 20 };
    std::ostringstream oss;

    // 1. 使用对象未重载 << 操作符
    oss << info1._name << " " << info1._age;
    // 2. 使用对象已重载 << 操作符
    oss << " " << info1;
    std::string str = oss.str();
    std::cout << "序列化后的字符串: " << str << std::endl;

    // 反序列化
    PersonInfo info2;
    std::istringstream iss(str);
    iss.str(str);
    
 	return 0;
}

使用 stringstream类也可以达到同样的效果:

std::stringstream ss;
ss << info1; // 写入对象到字符串流
ss << " serialized"; // 追加一些文本

PersonInfo info3;
std::string additionalText;
ss >> info3 >> additionalText; // 从字符串流中读取对象和追加的文本

std::cout << "stringstream 读取的对象: " << info3._name << " " << info3._age << std::endl;
std::cout << "附加的文本: " << additionalText << std::endl;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/739388.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

未系安全带智能监测摄像机

未系安全带智能监测摄像机在现代安全管理中发挥着至关重要的作用。这些先进设备不仅仅是简单的监视工具&#xff0c;更是通过整合高级技术来提升工作效率和安全性&#xff0c;特别是在需要高度警惕的作业环境中尤为突出。 首先&#xff0c;这些智能监测摄像机配备了精准的视觉识…

PageOffice国产版在线编辑word文件

PageOffice国产版支持统信UOS、银河麒麟等国产操作系统。调用客户端WPS在线编辑word、excel、ppt等文件。在线编辑效果与本地WPS一致。如图所示&#xff1a; web系统集成pageofficeV6.0国产版的文档&#xff1a;PageOfficeV6.0国产版最简集成代码(Springboot) PageOffice最简集…

Python 的垃圾回收机制使用详解

概要 在Python编程中,内存管理是一个非常重要的方面。为了帮助开发者管理内存,Python引入了垃圾回收(Garbage Collection)机制。本文将详细介绍Python中的垃圾回收,包括其工作原理、垃圾回收算法以及如何在实际项目中使用和优化垃圾回收。 一、垃圾回收的概念 垃圾回收是…

似然 与 概率

概率似然概率函数与似然函数的关系似然与机器学习的关系最大似然估计 似然与概率分别是针对不同内容的估计和近似 概率 概率&#xff1a;概率表达给定参数 θ \theta θ下样本随机向量 X x \textbf{X} {x} Xx的可能性。 概率密度函数的定义形式是 f ( x ∣ θ ) f(x|\t…

AIGC发展方向和前景

引言 背景介绍 AIGC的定义及其发展历程 AIGC&#xff0c;即人工智能生成内容&#xff0c;是近年来在人工智能领域兴起的一项重要技术。它通过使用机器学习和深度学习等技术&#xff0c;使得计算机能够自动生成各种形式的数字内容&#xff0c;如文本、图像、音频和视频等。 …

机器学习之Kmeans丨集成学习丨决策树测试

选择题 下面属于决策树的后剪枝的是&#xff1f;【 正确答案: A】 A. 把数据集分成测试集和训练集&#xff0c;用测试集构建一个足够大的决策树&#xff0c;用测试集判断叶节点合并是否能降低误差。 B. 当树到达一定深度的时候停止生长。 C. 当前节点的样本数量小于某个阈值时&…

【Linux】基础 I / O

目录 一、C文件操作函数&#xff1a; 二、输入 / 输出 / 错误流&#xff1a; 三、系统文件 I/O open函数&#xff1a; write&#xff1a; read&#xff1a; close&#xff1a; 具体应用&#xff1a; 四、文件描述符(fd): 1、概念&#xff1a; 2、文件管理&#xff1…

详解 | DigiCert EV代码签名证书

简介 DigiCert EV 代码签名证书是一种高级别的代码签名证书&#xff0c;它不仅提供了标准代码签名证书的所有安全特性&#xff0c;还增加了额外的身份验证流程&#xff0c;以确保软件开发者或发布者的身份得到最严格验证。这对于提升软件的信任度、防止恶意篡改和确保下载安全…

AI大模型战争:通用与垂直,谁将领跑未来?

文章目录 &#x1f4d1;引言一、通用大模型&#xff1a;广泛适用&#xff0c;实力不容小觑1.1 强大的泛化能力1.2 广泛的适用场景 二、垂直大模型&#xff1a;专注深度&#xff0c;精准解决问题2.1 深度专注&#xff0c;精准度高2.2 快速落地与普及 三、通用与垂直&#xff1a;…

受用一生的三种顶级思维

斯坦福大学心理学教授卡罗尔德韦克在《终身成长》中提到&#xff1a; 决定人与人之间差异的&#xff0c;不是天赋&#xff0c;不是勤奋程度&#xff0c;而是思维模式。 在许多情况下&#xff0c;拥有恰当的思维方式&#xff0c;甚至比单纯的努力更加关键。 普通的人改变结果…

通配符SSL证书与多域名SSL证书:理解它们的不同之处

在数字化的时代&#xff0c;网络安全已成为企业不可忽视的关键要素。SSL证书作为网站加密的重要工具&#xff0c;扮演着保护用户数据安全、提升网站信任度和搜索引擎排名的重要角色。然而&#xff0c;在众多SSL证书类型中&#xff0c;通配符SSL证书与多域名SSL证书因其独特优势…

竞赛选题 python 机器视觉 车牌识别 - opencv 深度学习 机器学习

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于python 机器视觉 的车牌识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;3分 &#x1f9ff; 更多资…

【调试笔记-20240620-Windows- Tauri + Vue 中实现部分区域滚动】

调试笔记-系列文章目录 调试笔记-20240620-Windows- Tauri Vue 中实现部分区域滚动 文章目录 调试笔记-系列文章目录调试笔记-20240620-Windows- Tauri Vue 中实现部分区域滚动 前言一、调试环境操作系统&#xff1a;Windows 10 专业版调试环境调试目标 二、调试步骤搜索相似…

基于自主发明专利的杰林码哈希算法、对称加密算法和无损压缩算法的可文件追踪管控且支持linux和windows的文件压缩包工具SDK和JLM PACK软件介绍

基于自主发明专利的杰林码哈希算法、对称加密算法和无损压缩算法的可文件追踪管控且支持linux和windows的文件压缩包工具SDK1.0版发布&#xff0c;下载链接为&#xff1a; JLM PACK CSDN下载链接 JLM PACK SDK和软件的官方网站 注意测试授权证书yesine_jlmpack_test.license…

生产实习Day13 ---- 神经网络模型介绍

文章目录 传统的神经网络模型注意力机制的引入注意力机制的本质Encoder-Decoder 框架注意力机制在 Encoder-Decoder 中的应用Self-Attention 机制Transformer 模型注意力机制的优势总结 传统的神经网络模型 在深度学习中&#xff0c;传统的神经网络模型&#xff0c;如循环神经…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 任务积分优化问题(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📎在线评测链接 任务积分优化问题(100分) 🌍 评测功能需要 订阅专栏 后私信…

React+TS前台项目实战(十四)-- 响应式头部导航+切换语言相关组件封装

文章目录 前言Header头部相关组件1. 功能分析2. 相关组件代码详细注释3. 使用方式4. Gif图效果展示 总结 前言 在这篇博客中&#xff0c;我们将封装一个头部组件&#xff0c;根据不同设备类型来显示不同的导航菜单&#xff0c;会继续使用 React hooks 和styled-components库来…

13.1.k8s集群的七层代理-ingress资源(进阶知识)

目录 一、ingress概述 1.前言 2.问题 3.ingress资源 二、ingress-nginx是什么 三、ingress-nginx 实现原理 四、部署ingress-nginx 1.获取部署文件 ingress-nginx.yaml 2.部署ingress-nginx 3.检查部署是否成功 五、编写使用Ingress样例代码 1.Ingress资源对象yaml文…

让生产管理变简单

随着业务的发展&#xff0c;工厂每天要处理很多订单&#xff0c;还要统筹安排各部门工作以及协调上下游加工企业&#xff0c;生产管理问题也随之而来。 1.销售订单评审困难、无法及时抓取到历史数据做参考。由于数据的不及时性、不准确性无法为正常的生产和采购提供数据支撑。同…

佳裕达物流:披露风险,负债1.26亿,营收下滑,净利润下滑-5925.93%

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 一、佳裕达物流公司介绍 佳裕达物流成立于2009年&#xff0c;总部位于广东省深圳市&#xff0c;是中国领先的端到端供应链解决方案供应商之一。 现已发展成为立足粤港澳大湾区、面向全国、布局全球的大型AAAA级综合服务型…