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

news2024/11/18 9:34:31

文章目录

  • 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;

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GD32 串口接受异常的几个原因

前面我们介绍过GD32 485发送时出现异常的最常见原因&#xff0c;有小伙伴反馈想要知道GD32 串口接受异常的可能原因&#xff0c;今天我们就来安排。 一、波特率异常导致收发出错 我们知道&#xff0c;串口是异步通讯接口&#xff0c;通讯双方或者多方都需要工作在相同波特率下…

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C学习 贝蒂的主页&#xff1a;Betty’s blog 1. 泛型编程 首先让我们来思考一个问题&#xff0c;如何实现一个交换函数&#x…

(超详细)YOLOV7改进-Soft-NMS(支持多种IoU变种选择)

1.在until/general.py文件最后加上下面代码 2.在general.py里面找到这代码&#xff0c;修改这两个地方 3.之后直接运行即可

对撞指针技巧

对撞指针技巧 我们以LeetCode的一道题目来讲解一下对撞指针&#xff1b; LeetCode第27题移除元素&#xff0c;链接如下&#xff1a; https://leetcode.cn/problems/remove-element 如果使用快慢指针 如果使用快慢指针&#xff0c;将会有大量的后面元素赋值给前面元素的操作…

面向二级及二级以下医院的云HIS系统源码,涵盖患者、费用、医嘱、电子病历等核心业务功能。

云HIS系统源码&#xff0c;二级医院信息管理系统源码&#xff0c;电子病历系统 云HIS系统&#xff0c;采用云计算、互(物)联网、大数据、人工智能等现代信息技术&#xff0c;融合医保、医疗、医药全方位的管理和服务&#xff0c;为各类中小型医疗机构&#xff0c;包括二级及二…

【Python机器学习实战】 | 基于K近邻算法和一般线性回归算法对电视剧播放数据进行回归预测

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

unity-特效-雷达扫描效果

使用后处理方式制作 using System; using System.Collections; using System.Collections.Generic; using UnityEngine;public class GlobalScanEffect : MonoBehaviour {public float startScanRange 0;public float maxScanRange 20;public float scanWidth 3;public flo…

数据库期末复习知识点

A卷 1. 选择题(30) 2. 判断范式(10) 判断到第三范式 3. 程序填空(20) 4. 分析填空(15) 5. 写SQL(25) 5一题 恶性 B卷 1. 单选(30) 2. 填空 (20) 3. 程序填空(20) 4. 写SQL(30) 知识点 第一章 数据库管理系统(DBMS) 主要功能 数据定义功能 (DDL, 数据定义语言, …

第二证券股市知识:小白炒股是做长线好还是短线好?

关于小白来说&#xff0c;挑选炒长线比炒短线要好一些&#xff0c;其间原因如下&#xff1a; ​ 1、对出资者技能要求相对较低 短线出资&#xff0c;需要出资者对个股的走势掌握比较精确&#xff0c;才干通过高抛低吸赚取必定的差价&#xff0c;否则很容易让散户卖飞个股&am…

快速记忆成百上千个账号密码

在日常生活中&#xff0c;我们不仅需要记忆6位数字的银行卡密码&#xff0c;还需要记忆各式各样网站和应用的账号密码&#xff0c;可能我们自己也不记得曾经注册过多少个账号。账号和密码如此繁多&#xff0c;管理这些账号和密码&#xff0c;也是一个让人头疼的问题。 最原始的…

前两天上线了一个小功能,差点把我们项目搞崩溃

项目场景&#xff1a; 最近一直在迭代公司的系统&#xff0c;业务提出需要增加一个消息通知的功能&#xff0c;对接完需求之后&#xff0c;我们就 开始热火朝天的编码、测试、上线&#xff0c; 就是右上角这个小图标&#xff0c;为了提升用户体验&#xff0c;我们采用每隔20S…

有效利用MRP能为中小企业带来什么?

在离散制造企业&#xff0c;主流的生产模式主要为面向订单生产和面向库存生产&#xff08;又称为预测生产&#xff09;&#xff0c;在中小企业中&#xff0c;一般为面向订单生产&#xff0c;也有部分面向库存和面向订单混合的生产方式&#xff08;以面向订单为主&#xff0c;面…

windows系统docker镜像导出

docker镜像导入导出(windows)_windowdocker下载镜像导出-CSDN博客https://blog.csdn.net/qq_22211217/article/details/93936363

网页设计软件Bootstrap Studio6.7.1

Bootstrap Studio是一个适用于Windows的程序,允许您使用流行的fre***orca Bootstrap创建和原型网站。您可以将现成的组件拖动到工作区并直观地自定义它们。该程序生成干净和语义的PDF、CSS和JS代码,所有Web浏览器都支持这些代码。 Bootstrap Studio有一个漂亮而强大的界面,它…

[个人感悟] MySQL应该考察哪些问题?

前言 数据存储一直是软件开发中必不可少的一环, 从早期的文件存储txt, Excel, Doc, Access, 以及关系数据库时代的MySQL,SQL Server, Oracle, DB2, 乃至最近的大数据时代f非关系型数据库:Hadoop, HBase, MongoDB. 此外还有顺序型数据库InfluxDB, 图数据库Neo4J, 分布式数据库T…

linux系统指令查漏补缺

目录 一.磁盘操作 二.lvm 三.top 4.nohup 一.磁盘操作 1. lsblk -f 显示磁盘和它的相关内容 2.tuen2fs -c -1 /dev/sdx 关闭某个磁盘的自检 3.修改配置&#xff0c;使文件系统不要开机自检 cat /etc/fstab 全0表示开机不自检 全1表示开机自检 同时在这个文件中可添加…

计算机网络面试HTTP篇二

HTTP/1.1 如何优化&#xff1f; 问你一句&#xff1a;「你知道 HTTP/1.1 该如何优化吗&#xff1f;」 我们可以从下面这三种优化思路来优化 HTTP/1.1 协议&#xff1a; 尽量避免发送 HTTP 请求&#xff1b;在需要发送 HTTP 请求时&#xff0c;考虑如何减少请求次数&#xff…

Nature推荐的三种ChatGPT论文写作指令

1. 润色学术论文 ChatGPT学术润色指令&#xff1a; “I’m writing a paper on [topic]for a leading [discipline] academic journal. WhatItried to say in the following section is [specific point]. Please rephrase itfor clarity, coherence and conciseness, ensuri…

C语言---数据结构(1)--时间复杂和空间复杂度计算

1.什么是时间复杂度和空间复杂度 1.1算法效率 算法效率分为时间效率和空间效率 时间效率被称为时间复杂度&#xff0c;而空间效率被称作空间复杂度。 时间复杂度主要衡量的是一个算法的运行速度&#xff0c;而空间复杂度主要衡量一个算法所需要的额外空间&#xff0c;在计算…

麦肯锡:量子传感究竟在何处可以发光发热

量子传感技术已经提供价值&#xff0c;潜在的应用案例可以塑造多个行业。有四种核心技术具有应用前景&#xff1a;固态自旋、中性原子、超导电路和离子阱&#xff0c;它们具有在广泛的物理属性上的传感能力&#xff0c;包括磁场、电场、旋转、温度、重力、时间和压力。选择哪种…