当前位置: 首页 > news >正文

C++(C++的文件I/O)

一、C++的文件IO

在C++中把文件的读写操作都封装在标准库中,ifstream类主要用于读取文件内容,ofstream主要用于写入文件内容,fstream类可读可写。

打开文件操作:
1、使用构造函数打开文件
fstream(const char *filename, openmode mode);
功能:创建操作文件的类对象,并顺便打开文件
filename:文件的路径
mode:打开的方式或权限默认参数是:O_RDWRios::app 添加输出,O_WRONLY|O_CREAT|O_APPEND ios::in 为读取打开文件 O_RDONLYios::out 为写入打开文件 O_WRONLY|O_CREAT|O_TRUNCios::binary 以二进制模式打开文件,相当于C语言中fopen函数的带b的打开方式ios::ate 当已打开时寻找到EOF,打开文件后顺序设置文件位置指针ios::trunc 文件存在则清空文件 O_TRUNC
​
ifstream( const char *filename, openmode mode);
mode默认参数是:O_RDONLYofstream( const char *filename, openmode mode);
mode默认参数是:O_WRONLY|O_CREAT|O_TRUNC
2、使用open成员函数打开文件
void open( const char *filename);
void open( const char *filename, openmode mode);
功能:与构造函数参数相同
3、如何判断文件打开成功或失败
方法1:直接使用类对象进行逻辑判断,因它们重载逻辑运算符。
方法2:调用good函数,该函数用于判断对象的上一次操作是否成成功,所以也可判断文件打开是否成功。
文本格式读写:

注意:像使用cout一样写入数据,使用cin一样读取数据。

注意:如果需要对一个结构、类进行文本格式读写,最好给它重载输入、输出运算符,不光cin、cout可以使用,ofstream、ifsteam也可以使用。

练习1:设计一个员工类,写入若干个员工信息到emp.txt文件,然后再读取出来测试是否写入成功。

二进入格式读写:

注意:如果是在Windows系统下读写二进制文件,mode参数中要有ios::binary,就像在C语言中要加b。

istream& read( char *buffer, streamsize num );
功能:读取一块数据到内存
buffer:一般情况下需要强制类型转换,特别是结构对象或类对象。
注意:返回值与标准C和Linux系统读取函数不同,需要调用gcount函数获取读取了多少个字节数据。
​
ostream& write(const char *buffer, streamsize num);
功能:把一块内存中的数据写入文件
注意:返回值与标准C和Linux系统读取函数不同,需要调用good函数判断写入是否成功。

注意:如果结构、类成员中有指针成员或string类的成员变量,不能以二进制格式直接把对象保存到文件中,最好以文本格式保存。

练习:使用C++语言实现cp命令。

随机读写:
istream &seekg( off_type offset, ios::seekdir origin );
ostream &seekp( off_type offset, ios::seekdir origin );
功能:以偏移值+基础位置设置文件的位置指针,之所以这样设计是为了兼容那些有两个文件位置(读写分开)操作系统,使用方法与lseek、fseek类型。
ios::seekdir originios::beg SEEK_SETios::cur SEEK_CURios::end SEEK_END
​
istream &seekg( pos_type position );
ostream &seekp( pos_type position );
功能:以绝对位置设计文件的位置指针
pos_type:把文件的位置指针移动到文件的第几个字节。
​
pos_type tellg();
pos_type tellp();
功能:获取文件的位置指针,与ftell函数的功能相同。
注意:由于操作系统的文件位置指针是两个,读取各一个,所有C++语言提供了两g和p两套位置指针函数,但在Linux系统和Windows系统下,读写操作共用一个位置指针,所以使用p、g没有区别。

特殊格式的读写:
fmtflags flags();
fmtflags flags( fmtflags f );
功能:获取当前流的格式标志
​
fmtflags setf( fmtflags flags );
fmtflags setf( fmtflags flags, fmtflags needed );
功能:设置当前流的格式化标志为flags
​
void unsetf( fmtflags flags );
清除与当前流相关的给定的标志flags 
操作符描述输入输出
boolalpha启用boolalpha标志XX
dec启用dec标志XX
endl输出换行标示,并清空缓冲区X
ends输出空字符X
fixed启用fixed标志X
flush清空流X
hex启用 hex 标志XX
internal启用 internal 标志X
left启用 left 标志X
noboolalpha关闭boolalpha 标志XX
noshowbase关闭showbase 标志X
noshowpoint关闭showpoint 标志X
noshowpos关闭showpos 标志X
noskipws关闭skipws 标志X
nounitbuf关闭unitbuf 标志X
nouppercase关闭uppercase 标志X
oct启用 oct 标志XX
right启用 right 标志X
scientific启用 scientific 标志X
showbase启用 showbase 标志X
showpoint启用 showpoint 标志X
showpos启用 showpos 标志X
skipws启用 skipws 标志X
unitbuf启用 unitbuf 标志X
uppercase启用 uppercase 标志X
ws跳过所有前导空白字符X
#include <iostream>
using namespace std;
​
int main(int argc,const char* argv[])
{/*printf("|%4d|\n",1);    cout << "|";cout.width(4);cout << 1 << "|" <<  endl;*/int num = 0x01020304;printf("%x\n",num);cout << hex << num << endl;bool flags = false;cout << boolalpha << flags << endl;return 0;
}

二、 异常处理

什么是异常处理:

从宏观角度来说,异常处理就是当程序执行过程中出现了错误,以及对错误的处理方案。

C语言的异常处理:

C语言一般通过函数返回值、信号,来表示程序在运行过程中出现的错误。

例如:

文件打开失败,fopen、open函数的返回值来判断文件打开是否成功。

缺点:返回的类型单一,返回的数据很难跨作用域,还需要考虑它们的成功情况,必须使用if、switch对返回值进行判断。

断错误、非法硬件指令、总线错误、浮点异常等代码执行过程中出现错误信息。

缺点:错误信息过于简单,捕获处理完后进行依然需要结束。

C++语言的异常处理:
1、如何抛异常

throw 数据;

类似return语句返回一个数据,但不同时它可以返回任何类型的数据,并且可以不需要预告声明。

注意:throw与return最大区别是,throw返回的数据,上层必须处理,否则程序会立即结束(核心已转储)。

2、声明异常

1、所谓的异常声明,就是函数的实现者对调用者的一种承诺,我会抛哪些类型的导常

返回值类型 函数名(参数列表) throw(类型,...)
{
​
}

2、如果函数不进行异常声明,则表示可能会抛出任何类型的异常。

3、如果抛出了声明以外的异常,编译不会出错,但无法捕获,即使你写的准确捕获语句,也无法捕获,也就是说如果函数的实现者不遵守承诺,调用它的程序只有死路一条。

4、throw() 表示不会抛出任何异常,请放心调用。

size_t file_size(const char* filename)
{throw 1234;ifstream ifs(filename);if(!ifs){throw string("文件打开失败!");}
​ifs.seekg(0,ios::end);return ifs.tellg();
}
​
int main(int argc,const char* argv[])
{try{cout << file_size("eheheheheh") << endl;}catch (int num){cout << "我就知道你不靠谱" << num << endl;}catch (string str){cout << str << endl;}return 0;
}

5、类成员函数的异常声明列表如果不同,会影响函数覆盖,如果其它条件都符,只有异常声明列表不同,编译会出错误。

#include <iostream>
using namespace std;
​
class A
{
public:virtual void func(void) throw(){   cout << "我是A类的func函数" << endl;}   
};
​
class B : public A
{
public:void func(void) throw(){   cout << "我是B类的func函数" << endl;}   
};
​
int main(int argc,const char* argv[])
{A* a = new B;a->func();return 0;
}
3、捕获异常
try{可能产生异常的函数调用、代码。
}
catch(类型1 变量名){1、处理异常2、继续往上抛
}
catch(类型2 变量名){1、处理异常2、继续往上抛
}
...
int main(int argc,const char* argv[])
{ int* p;try{p = new int[0xffffffff];}catch(bad_array_new_length error){cout << "申请内在失败" << endl;cout << error.what() << endl;}
}

注意:如果继续往上抛的异常,没有被处理,那么程序将停止执行(我个人习惯,只在main函数内进行异常捕获)。

4、抛异常和捕获异常要注意的问题

1、捕获异常时要先尝试捕获子类异常变量,再捕获父类异常变量,因为catch不会挑选最合适的,而从上到下选择一个可以捕获的类型,或者只写捕获父类异常变量,这样返回父类异常和子类异常都可以兼容。

2、不要在异常类的构造函数的析构函数中抛出异常,如果该类对象就是异常数据,那么会在抛异常的过程中产生新的异常(指的设计异常类,暂时不需要掌握)。

3、不要抛指针类型的异常,因为我们的异常是跨作用域的,当捕获者获得异常后,指针指向的内存可能已经释放,那么捕获的指针就可能是野指针(异常会一层层往上抛,要么被捕获,要么是抛到main函数中,程序死掉)。

4、尽量使用类名创建临时的类对象进行抛异常,使用引用来捕获异常,因为这样既避免调用拷贝构造函数,也避免对象出了作用域后被释放产生悬空引用。

5、不需要抛基本类型的异常数据,如果想抛自定义的异常,建议封装成异常类,并且该类继承exception类,这样我们只需要在main函数中写一份异常捕获即可。

C++标准异常:

所谓的C++标准异常就是在使用C++标准库中的函数、类、类对象、new、delete时可能抛出的异常,简称C++标准异常。

异常描述
std::exception该异常是所有标准 C++ 异常的父类。
std::bad_alloc该异常可以通过 new 抛出。
std::bad_cast该异常可以通过 dynamic_cast 抛出。
std::bad_exception这在处理 C++ 程序中无法预期的异常时非常有用。
std::bad_typeid该异常可以通过 typeid 抛出。
std::logic_error理论上可以通过读取代码来检测到的异常。
std::domain_error当使用了一个无效的数学域时,会抛出该异常。
std::invalid_argument当使用了无效的参数时,会抛出该异常。
std::length_error当创建了太长的 std::string 时,会抛出该异常。
std::out_of_range该异常可以通过方法抛出,例如 std::vector 和 std::bitset<>::operator。
std::runtime_error理论上不可以通过读取代码来检测到的异常。
std::overflow_error当发生数学上溢时,会抛出该异常。
std::range_error当尝试存储超出范围的值时,会抛出该异常。
std::underflow_error当发生数学下溢时,会抛出该异常。
#include <exception>
using namespace std;
​
int main(int argc,const char* argv[])
{// 只要是C++标准异常,该方法都可以捕获try{// int* p = new int[0xffffffff];// string str(0xffffffff,'x');int a = 1234 , b = 0;int c = a / b;}   catch (exception& ex) {   cout << ex.what() << endl;}   return 0;
} 
自定义的通用异常类
#ifndef MY_ERROR_H
#define MY_ERROR_H
#include <iostream>
using namespace std;
​
class MyError:public exception
{string whatInfo;
public:MyError(const char* file,const char* func,size_t line,const char* info){whatInfo = file;whatInfo += " ";whatInfo += func;whatInfo += " ";char buf[21];sprintf(buf,"%u",line);whatInfo += buf;
​whatInfo += ":";whatInfo += info;}
​~MyError(void) throw() {}
​const char* what(void)const throw(){return whatInfo.c_str();}
};
​
#define Error(info) MyError(__FILE__,__func__,__LINE__,info)
​
#endif//MY_ERROR_H

C++中的异常处理与C语言的错误处理的区别?

throw是在return语句的基础上实现了,都是向调用返回一个数据。

1、throw可以返回多种类型数据,而return只能返回一种。

2、return返回的数据可以不处理,throw返回的数据必须处理,否则程序停止运行。

3、return返回的数据给调用者,throw返回的数据可以一层一层向上返回,直到被捕获处理。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3566移植案例(下)
  • 苹果macOS 15.0 Sequoia正式版发布:iPhone应用镜像玩、手机消息电脑知
  • 二叉树的前中后序遍历(迭代法)( 含leetcode上三道【前中后序】遍历题目)
  • WPF自定义Dialog模板,内容用不同的Page填充
  • OJ题-合并K个已排序的链表
  • libmodbus:写一个modbusTCP服务
  • 【AI学习】AI绘画发展简史
  • Unreal像素流ubantu os部署细节
  • 使用Maven创建一个Java项目并在repository中使用
  • qwen2 VL 多模态图文模型;图像、视频使用案例
  • ElK 8 收集 Nginx 日志
  • windows server2012 配制nginx安装为服务的时候,直接跳要安装.net框架,用自动的安装,直接失败的解决。
  • 从入门到精通,带你探索适合新手的视频剪辑工具
  • STM32快速复习(十二)FLASH闪存的读写
  • 海外服务器哪个速度最快且性能稳定
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • 08.Android之View事件问题
  • Apache Zeppelin在Apache Trafodion上的可视化
  • Gradle 5.0 正式版发布
  • JAVA SE 6 GC调优笔记
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • 分布式任务队列Celery
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 微服务核心架构梳理
  • 智能合约Solidity教程-事件和日志(一)
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • 说说我为什么看好Spring Cloud Alibaba
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • ​ubuntu下安装kvm虚拟机
  • #QT 笔记一
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • (2022 CVPR) Unbiased Teacher v2
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (4.10~4.16)
  • (二) 初入MySQL 【数据库管理】
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (三)SvelteKit教程:layout 文件
  • (三)模仿学习-Action数据的模仿
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (源码分析)springsecurity认证授权
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • (轉貼)《OOD启思录》:61条面向对象设计的经验原则 (OO)
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NET3.5下用Lambda简化跨线程访问窗体控件,避免繁复的delegate,Invoke(转)
  • .Net6支持的操作系统版本(.net8已来,你还在用.netframework4.5吗)
  • .net分布式压力测试工具(Beetle.DT)
  • .net后端程序发布到nignx上,通过nginx访问
  • .NET设计模式(2):单件模式(Singleton Pattern)
  • @Repository 注解
  • [ 英语 ] 马斯克抱水槽“入主”推特总部中那句 Let that sink in 到底是什么梗?
  • [2019红帽杯]Snake
  • [AIGC] 广度优先搜索(Breadth-First Search,BFS)详解