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

C++核心编程 day09 类型转换、异常、输入输出流

C++核心编程 day09 类型转换、异常、输入输出流

  • 1. 类型转换
  • 2. 异常
    • 2.1 异常语法
    • 2.2 C++标准异常库
  • 3. 输入输出流
    • 3.1 输入输出流概念以及流类库
    • 3.2 标准输入流
    • 3.3 标准输出流
    • 3.4 文件读写

1. 类型转换

C++中的类型转换有四类,分别是静态转换、动态转换、常量转换、重新解释转换。

静态转换使用static_cast<typename>进行转换。主要用于类层次中的父类和子类之间指针或引用的转换。向上类型转换的时候是安全的,但是向下类型转换的时候由于没有动态类型检查,所有是不安全的。静态转换也支持内置基本的数据类型之间的转换。

动态类型转换是使用dynamic_cast<typename>进行转换。动态类型转换用于类层次之间的向上类型转换和向下类型转换。向上类型转换的时候效果和静态类型转换的效果是一样的。在使用向下类型转换的时候,会比static_cast更加安全。动态类型转换不支持内置基本数据类型转换。

常量转换是用于修改类型的const属性,使用const_cast<typename>来进行转换。需要注意的是常量转换不能直接对非指针和非引用的变量去移除他们的const属性。

重新解释转换是使用reinterpret_cast<typename>来进行转换。这是C++中最不安全的一种转换机制,最有可能出问题。主要用于将一种数据类型转换为另一种数据类型,比如指针可以转换为一个整数,一个整数也可以转换为一个指针。

关于四种类型转换的示例代码如下所示。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;//静态类型转换
void test01()
{//允许内置数据类型之间转换char a = 'a';double d = static_cast<double>(a);cout << d << endl;
}class Base{ virtual void func(){} };
class Son : public Base { virtual void func(){} };
class Other {};void test02()
{Base *base = NULL;Son *son = NULL;//语法:static_cast<目标数据类型>(原对象)//父子之间的指针或者引用可以转换//将base转为Son * 父转子 向下类型转换 不安全Son *son2 = static_cast<Son *>(base);//son转为Base * 子转父 向上类型转换 安全Base *base2 = static_cast<Base *>(son);//base转为Other *//Other *other = static_cast<Other *>(base); //转换无效
}// 动态类型转换 dynamic_cast
void test03()
{//不允许内置数据类型之间转换//char c = 'c';//double d = dynamic_cast<double>(c);
}void test04()
{Base *base = new Base;Son *son = NULL;//将base转为Son * 父转子 不安全 如果发生了多态,那么转换总是安全的Son *son2 = dynamic_cast<Son *>(base);//son转为Base * 子转父 安全Base *base2 = dynamic_cast<Base *>(son);//base转Other *//Other *other = dynamic_cast<Other *>(base); //无法转换
}//常量转换 const_cast
void test05()
{//不可以将非指针或者费引用做const_cast转换const int *p = NULL;int *pp = const_cast<int *>(p);const int *ppp = const_cast<const int *>(pp);//const int a = 10;//int b = const_cast<int>(a);int num = 10;int &numRef = num;const int &num2 = const_cast<const int &>(numRef);
}//重新解释转换 reinterpret_cast 最不安全一种转换,不建议使用
void test06()
{int a = 10;int *p = reinterpret_cast<int *>(a);Base *base = NULL;//base转Other *Other *other = reinterpret_cast<Other *>(base);
}int main()
{test01();system("pause");return 0;
}

2. 异常

2.1 异常语法

异常处理就是处理程序中出现的错误,所谓的错误就是程序运行过程中发生的一些异常事件。比如除0移除、数组下标越界、空指针等错误。在C语言中我们对错误的处理主要是两个方法,第一种是使用整型的返回值标识错误,二是使用errno宏去记录错误。在C++中仍然可以使用这两种方法。

上述的两种处理方法虽然说可以处理错误,但是最大的缺陷就会出现不一致的错误。比如有些函数返回1表示成功,返回0表示错误;而有些函数返回0表示成功,返回非0表示错误。除此之外,还有一个缺陷就是函数的返回值只有一个,当你通过函数的返回值代表错误代码的时候,那么函数就不能返回其他的值。比如下面的函数你就不能分清该函数返回的-1究竟是程序出错还是程序的执行结果。也就是函数的返回值有多重语义。

int myDivision(int a, int b)
{if(b == 0){return -1;}return a / b;
}

而我们使用C++的异常处理就不会出现这种情况。在C语言中处理异常的时候可能函数的调用者会忘记处理异常,而C++中如果你没有处理异常程序就会中断。异常的处理也可以在处理跳级,也就是有多个函数在调用栈中出现了某个错误,而C++中只需要在其中的某一处进行处理即可,不需要每一级的函数都进行处理。C++中如果有异常,我们使用throw操作创建一个异常对象并抛出。我们将可能抛出异常的程序段放在try代码块中,如果在try程序段执行期间没有引起异常,那么跟在try代码段后的catch字句就不会执行。catch子句会根据出现的先后顺序被检查,匹配的catch语句捕获并处理异常,或者也可以继续抛出异常。如果匹配的处理未找到,则会自动调用terminate函数,其缺省功能调用abort终止程序。对于处理不了的异常,也可以在最后一个catch分支使用throw继续上抛。下面给出一段关于异常的基本语法的示例代码。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <string>class MyException
{
public:void printError(){cout << "我自己的异常" << endl;}
};class Person
{
public:Person(){cout << "Person的默认构造函数调用" << endl;}~Person(){cout << "Person的析构函数调用" << endl;}
};int myDivision(int a, int b)
{if (b == 0){//return -1;//throw 1; //抛出int类型异常//throw 'a'; //抛出char类型异常//throw 3.14; //抛出double类型异常//string str = "abc";//throw str;//从try代码开始,到throw抛出异常之前,所有栈上的数据都会被释放掉//释放的顺序和创建的顺序相反,这个过程我们称为栈解旋Person p1;Person p2;throw MyException(); //抛出MyException的匿名对象}return a / b;
}void test01()
{int a = 10;int b = 0;//C语言处理异常有缺陷,返回值不统一,返回值只有一个,无法区分是结果还是异常//int ret = myDivision(a, b);//if (ret == -1)//{//	cout << "异常" << endl;//}try{myDivision(a, b);}catch (int){cout << "int类型异常捕获" << endl;}catch (char){cout << "char类型异常捕获" << endl;}catch (double){//捕获到了异常,但是不想处理,继续向上抛出这个异常//异常必须有函数进行处理,如果没有任何处理,程序自动调用terminate函数,让程序中断throw;cout << "double类型异常捕获" << endl;}catch (MyException e){e.printError();}catch (...){cout << "其他类型异常捕获" << endl;}}int main()
{try{test01();}catch (double){cout << "main函数中double类型异常捕获" << endl;}catch (...){cout << "main函数中其它类型异常捕获" << endl;}system("pause");return 0;
}

C++中异常机制和函数机制并不互相干涉,但是捕获方式是通过严格的类型匹配。

异常被抛出后,从进入try代码块开始,到异常被抛掷之前,这期间在栈上构造的所有对象都会被自动析构。析构的顺序与构造的顺序相反,这一过程被称为栈的解旋。

为了加强程序的可读性,我们也可以在函数申明中列出可能抛出的异常的所有类型,例如void func() throw(A, B, C);这个函数func只能抛出类型为A、B、C以及其子类类型的异常。如果throw后的括号为空,则这个函数不能够抛出任何异常。如果函数的声明中没有包含结构声明,则函数可以抛出任意类型的异常。如果一个声明了接口的函数抛出了不允许抛出的异常,则会调用unexpected函数,该函数的默认行为是调用terminate函数中断程序。异常变量也是有声明周期的,声明周期和之前将的普通变量是类似的。异常变量也是有生命周期的,示例代码如下。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <string>class MyException
{
public:MyException(){cout << "MyException默认构造函数调用" << endl;}MyException(const MyException &e){cout << "MyException拷贝构造函数调用" << endl;}~MyException(){cout << "MyException析构函数调用" << endl;}
};void doWork()
{throw new MyException();
}int main()
{try{doWork();}//抛出的是throw MyException(); catch(MyException e) 调用拷贝构造函数,效率低//抛出的是throw MyException(); catch(MyException &e) 只调用默认构造,效率高推荐//抛出的是 throw &MyException(); catch(MyException *e) 对象会提前释放掉,不能在非法操作//抛出的是 new MyException(); catch(MyException *e) 只调用默认构造函数 自己要管理释放catch (MyException *e){cout << "自定义异常捕获" << endl;delete e;}system("pause");return 0;
}

异常也是有多态的,父类的引用或者指针指向子类的对象。使用的方法和前面类中的多态是一样的,在异常捕获的时候,我们常用这个,示例代码如下。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;//异常的基类
class BaseException
{
public:virtual void printError() = 0;
};//空指针异常
class NULLPointerException :public BaseException
{
public:virtual void printError(){cout << "空指针异常" << endl;}
};//越界异常
class OutOfRangeException :public BaseException
{
public:virtual void printError(){cout << "越界异常" << endl;}
};void doWork()
{//throw NULLPointerException();throw OutOfRangeException();
}int main()
{try{doWork();}catch (BaseException &e){e.printError();}system("pause");return 0;
}

2.2 C++标准异常库

除了前面的自己编写的异常之外,标准库中也为我们提供了很多的异常类,他们是通过类的继承组织起来的。

在这里插入图片描述
所有的异常都继承一个公共的基类exception。每个类都有提供的了构造函数、拷贝构造函数和赋值操作。其中在logic_error类与runtime_error类以及它们的子类都有一个构造函数接收一个string类型参数用于描述异常的信息。所有的异常都有一个what()函数,该函数是一个常函数,返回的是const char *类型的值用于描述异常的信息。所有我们要输出异常的信息可以通过打印异常类中的what()函数的返回值即可。下面给出一些标准异常类的描述:

异常名称描述
exception所有标准异常类的基类
bad_alloc在堆区开辟内存失败的时候,比如使用new或者new[]申请空间
bad_exception当函数的接口声明了抛出bad_exception异常,而函数中抛出了接口没有声明的异常,调用unexpected函数若抛出异常,则无论什么异常都会被自动替换被bad_exception类型异常
bad_cast使用动态类型转换引用失败的时候抛出的异常
ios_base::failureIO操作过程中出现错误
logic_error逻辑错误,也在运行前检测的错误
length_error试图生成一个操作该类型最大长度的对象抛出的异常
domain_error参数的值域错误,主要出现在数学函数中
out_of_range超出有效范围
invalid_argument参数不合适
runtime_error运行时错误,在运行时才能检测到的错误
range_error计算结果超出了有意义的值域范围
overflow_error算术计算上溢
underflow_error算术计算结果下溢

例如下面代码就是用了系统标准库提供的异常类。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;class Person
{
public:Person(int age){if (age < 0 || age > 150){//throw out_of_range("年龄必须在 0 ~ 150 之间");throw length_error("年龄必须在 0 ~ 150 之间");}else{this->age = age;}}int age;
};int main()
{try{Person p(151);}catch (out_of_range &e){cout << e.what() << endl;}catch (length_error &e){cout << e.what() << endl;}system("pause");return 0;
}

标准库中的异常类是有限的,有时候我们也需要自己的异常类。在自己写异常类的时候,最好自己写的类要继承标准库中的异常类,同时也应该重载父类中的what函数,示例代码如下。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <string>class MyOutOfRangeException :public exception
{
public:MyOutOfRangeException(const char *str){//const char * 可以隐式类型转换为string, 反之不可以this->errorInfo = str;}MyOutOfRangeException(string str){this->errorInfo = str;}virtual const char * what() const{//将string转为const char *return this->errorInfo.c_str();}string errorInfo;
};class Person
{
public:Person(int age){if (age < 0 || age > 150){throw MyOutOfRangeException("年龄必须在0到150之间");}else{this->age = age;}}int age;
};int main()
{try{Person p(1000);}catch (exception &e){cout << e.what() << endl;}system("pause");return 0;
}

3. 输入输出流

3.1 输入输出流概念以及流类库

程序的输入是指从文件将数据输入给程序,而程序的输出是将数据从程序输出给文件。C++中的输入分为三类,分别是标准I/O、文件I/O、串I/O。标准I/O是对系统指定的标准设备的输入与输出,比如鼠标键盘显示器等。文件I/O是以外存磁盘文件为对象进行输入输出。串I/O是对内存中指定的空间进行输入和输出,通常以字符数组作为空间的形式。

C++中提供了用于标准输入输出的iostream类库,也提供了用于文件输入输出的fstream类库以及串输入输出的strstream类库。

在这里插入图片描述
在这里插入图片描述

我们来详细看一下其中的常见类名。

类名 |作用 | 头文件
ios | 抽象基类 | iostream
istream | 通用输入流和其它输入流的基类 | iostream
ostream | 通用输出流和其它输出流的基类 | iostream
iostream | 通用输入输出流和其它输入输出流的基类 | iostream
ifstream | 输入文件流类 | fstream
ofstream | 输出文件流类 | fstream
fstream | 输入输出文件流类 | fstream
istrstream | 输入字符串流类 | strstream
ostrstream | 输出字符串流类 | strstream
strstream | 输入输出字符串流类 | strstream

iostream类库中的不同的类声明放在不同的头文件中,用户在自己的程序中#include相关的头文件就相当于声明了所需要用到的类。常用的头文件有以下:

  • iostream:包含了对输入输出流进行操作的所需基本信息。
  • fstream:用于用户管理的文件的I/O操作。
  • strstream:用于字符串流I/O。
  • stdiostream:用于混合使用C和C++的I/O机制。
  • iomanip:在使用格式化I/O时应该包含此头文件。

iostream中有四种流对象,分别如下:

对象含义设备对应的类C语言中对应的标准文件
cin标准输入流键盘istream_withassignstdin
cout标准输出流屏幕ostream_withassignstdout
cerr标准错误流屏幕ostream_withassignstderr
clog标准错误流屏幕ostream_withassignstderr

cout是console output的缩写,意思是在控制台输出。cout不是关键字,而是ostream的一个对象,在iostream中有定义。在cout中重载了左移运算符用于输出。使用<<的时候用户可以不必考虑是什么类型,系统自动判断数据的类型并且根据其类型调用与之匹配的运算符重载函数。而在C语言中输出是非常麻烦的,因为需要记住很多格式字符。cout流在内存中对一个开辟了一个缓冲区,用于存放流中的数据,当cout流插入一个endl时,无论缓冲区是否满,都会立即输出流中的所有数据,然后插入一个换行符并清空缓冲区。

cerr流对象是标准错误流,cerr流被指定为与显示器相关联。作用是在标准错误设备上输出相关出错信息。cerr与标准输出流cout的作用和用法差不多,但是有一点不同。cout通常是传送到显示屏输出,也可以被重定向输出到磁盘文件,而cerr流中的信息只能在显示器上输出。

clog流对象也是标准错误流,是console log的缩写。它的作用和cerr的作用相同,都是在显示器终端上输出出错信息。但是不同的是cerr是不经过缓冲区直接向显示器输出有关信息,而clog中的信息放在缓冲区中,缓冲区满后或者遇到endl时向显示器输出。

3.2 标准输入流

标准输入流对象是cin,在里面有几个比较重点的函数。

  • cin.get() :一次从输入缓冲区内读取一个字符。
  • cin.get(n):一次从输入缓冲区内读取n个字符。
  • cin.get(buf, n):一次从输入缓冲区内读取长度为n个字符存入buf中。
  • cin.getline(buf, n):一次从输入缓冲区内读取一行的数据将最多n个存入buf中。
  • cin.ignore():忽略一个字符,如果括号有参数就是忽略n个字符。
  • cin.peek():偷窥输入缓冲区的第一个字符。
  • cin.putback(ch):将字符ch放回输入缓冲区。
  • cin.clear():清空缓冲区。
  • cin.sync():重置标志位,标志位为1表示异常,为0表示正常。
  • cin.fail():获取缓冲区标志位,返回的结果为0或者1

上述标准输入流对象的函数示例如下。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;/*
cin.get() //一次只能读取一个字符
cin.get(一个参数) //读取一个字符
cin.get(两个参数) //可以读字符串
cin.getline()
cin.ignore()
cin.peek()
cin.putback()
*/void test01()
{char c = cin.get();cout << "c = " << c << endl;c = cin.get();cout << "c = " << c << endl;c = cin.get();cout << "c = " << c << endl;c = cin.get();cout << "c = " << c << endl;
}void test02()
{char buf[1024] = { 0 };cin.get(buf, 1024);char c = cin.get();//利用cin.get获取字符串的时候,换行符遗留在缓冲区中if (c == '\n'){cout << "换行符遗留在缓冲区" << endl;}else{cout << "换行符不在缓冲区" << endl;}cout << buf << endl;
}void test03()
{char buf[1024] = { 0 };//利用cin.getline获取字符串时候,换行符不会被取走,也不再缓冲区中,而是直接扔掉cin.getline(buf, 1024);char c = cin.get();if (c == '\n'){cout << "换行符遗留在缓冲区" << endl;}else{cout << "换行符不在缓冲区" << endl;}cout << buf << endl;
}//cin.ignore忽略 默认忽略一个字符,如果填入参数X,代表忽略X个字符
void test04()
{cin.ignore(2);char c = cin.get();cout << "c = " << c << endl;
}//cin.peek 偷窥
void test05()
{char c = cin.peek();cout << "c = " << c << endl;c = cin.get();cout << "c = " << c << endl;c = cin.get();cout << "c = " << c << endl;
}//cin.putback() 返回
void test06()
{char c = cin.get();cin.putback(c);char buf[1024] = { 0 };cin.getline(buf, 1024);cout << buf << endl;
}//案例1. 判断用户输入的内容是字符串还是数字
void test07()
{cout << "请输入一个字符串或者数字" << endl;char c = cin.peek();if (c >= '0' && c <= '9'){int num;cin >> num;cout << "您输入的是数字 为: " << num << endl;}else{char buf[1024] = { 0 };cin >> buf;cout << "您输入的是字符串 : " << buf << endl;}
}// 案例2 用户输入0~1之间的数字,如果输入有误重新输入
void test08()
{cout << "请输入0 ~ 10之间的数字" << endl;int num;while (true){cin >> num;if (num >= 0 && num <= 10){cout << "输入正确, 输入的值为: " << num << endl;break;}// 清空缓冲区,重置标志位cin.clear();//cin.sync();//cin.ignore(); //vs2013以上版本加入// 如果标志位为0,代表缓冲区正常 如果标志位为1,缓冲区异常cout << "cin.fail() = " << cin.fail() << endl;cout << "输入有误,请重新输入:" << endl;}
}int main()
{//test01();//test02();//test03();//test04();//test05();//test06();//test07();test08();system("pause");return 0;
}

3.3 标准输出流

C++中的输出是通过标准输出流cout完成的。以下是关于标准输出流的函数。

  • cout.flush():刷新缓冲区。
  • cout.put(ch):向缓冲区中写入字符ch
  • cout.write(str, n):向缓冲区中输出str字符串的前n个字符。

在C语言中我们使用格式字符通过printf去控制输出的格式,在C++中我们通过流对象cout中用于控制输出格式的成员函数来控制输出格式。常见控制输出格式的成员函数如下:

流成员函数与之相同作用的控制符作用
precision(n)setprecision(n)设置实数的精度为n位
width(n)setw(n)设置字段宽度为n位
fill(c)setfill(c)设置填充字符c
setf()setiosflags()设置输出格式状态,括号中应给出格式状态,内容与控制符setiosflags括号中的内容相同
unsetf()resetiosflags()终止已设置的输出格式状态,在括号中应指定内容

流成员函数setf和控制符setiosflags库昊中的参数表示格式状态,它是通过格式标志来指定的。格式标志在类ios中被定义为枚举值,因此在引用这些的时候需要加上类名ios以及作用域运算符::,下面是格式标志。

格式标志作用
ios::left输出数据在本域宽范围内向左对齐
ios::right输出数据在本域宽范围内向右对齐
ios::internal数值的符号为应在域宽内左对齐,数值右对齐,中间由填充字符填充
ios::dec设置整数的基数为10
ios::oct设置整数的基数为8
ios::hex设置整数的基数为16
ios::showbase强制输出整数的基数(八进制数以0开头,十六进制数以0x开头)
ios::showpoint强制输出浮点数的小数和尾数0
ios::uppercase在以科学计数法格式E和以十六进制输出字母时以大写表示
ios::showpos对正数显示+号
ios::scientific浮点数以科学计数法格式输出
ios::fixed浮点数以定点格式(小数形式)输出
ios::unitbuf每次输出之后刷新所有的流
ios::stdio每次输出之后清除stdoutstderr

关于控制符如下:

控制符作用
dec设置数值的基数为10
hex设置数值的基数为16
oct设置数值的基数为8
setfill(c)设置填充字符c,c可以是字符常量或者字符变量
setprecision(n)设置浮点数的精度为n位。在以十进制小数形式输出时,n代表有效数字。在以fixed(固定小数位数)形式和scientific(指数)形式输出时,n为小数位数
setw(n)设置字段宽度为n位
setiosflags(ios::fixed)设置浮点数以固定的小数位显示
setiosflags(ios::scientific)设置浮点数以科学计数法(即指数形式) 显示
setiosflags(ios::left)输出数据左对齐
setiosflags(ios::right)输出数据右对齐
setiosflags(ios::skipws)忽略前导的空格
setiosflags(ios::uppercase)数据以十六进制形式输出时字母以大写表示
setiosflags(ios::lowercase)数据以十六进制形式输出时字母以小写表示
setiosflags(ios::showpos)输出正数时给出+号

需要注意的是如果使用了控制符,在程序开头还需要添加iomanip.h头文件。成员函数width(n)和控制符setw(n)只对其后面的第一个输出项有效。 在上面设置数值基数的只能选择其中一种来使用,它们是相互排斥的。对于成员函数setf和控制符setiosflags设置的输出格式状态,如果想要改变使用另一个状态,应该调用成员函数unsetf或者控制符resetiosflags终止原来设置的状态。在使用setf函数设置格式状态时,可以包含两个甚至多个状态,这些格式标志在ios类中被定义为枚举值,每一个格式标志都是以一个二进制位表示的,因此可以使用位运算符|组合多个格式标志。

关于输出流对象的示例代码如下。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <iomanip> // 控制符格式化输出 头文件/*
cout.put() //想缓冲区写入字符
cout.write() //从buffer中写num个字节到当前输出流中
*/
void test01()
{//cout.put('h').put('e');char buf[] = "hello world";cout.write(buf, strlen(buf));cout << "hello world" << endl;
}// 1.通过流成员函数格式化输出
void test02()
{int number = 99;cout.width(20); // 指定宽度为20cout.fill('*'); // 填充cout.setf(ios::left); // 左对齐cout.unsetf(ios::dec); // 卸载十进制cout.setf(ios::hex); // 安装十六进制cout.setf(ios::showbase); // 显示基数cout << number << endl;
}// 2. 使用控制符格式化输出
void test03()
{int number = 99;cout << setw(20)	// 设置宽度<< setfill('~') // 设置填充<< hex // 显示16进制<< setiosflags(ios::showbase) // 显示基数<< setiosflags(ios::left) // 左对齐<< number << endl;
}int main()
{//test01();//test02();test03();system("pause");return 0;
}

3.4 文件读写

文件读写主要在fstream.h头文件中被定义,这里面定义了三个类,分别是ifstreamofstreamfstream,它们之间的继承关系如下。

在这里插入图片描述
进行文件读写的第一步就是要先打开文件,打开文件有两种方法。

第一种是调用文件流对象的open成员函数,该函数的第一个参数文件路径,第二个参数是打开的方式。第二种方式使用文件流定义的参数构造函数,如下。

// 第一种方法
ofstream ofs;
ofs.open("./demo1.txt", ios::out);// 第二种方法
ofstream ofs("./demo1.txt", ios::out);

文件输入输出的方式设置值如下。

方式作用
ios::in以输入方式打开文件
ios::out以输出方式打开文件(这是默认方式),如果已经有此名字的文件,则将其原有内容直接全部清空
ios::app以输出方式打开文件,写入的数据添加在文件末尾
ios::ate打开一个已有的文件,文件指针指向文件末尾
ios::trunc打开一个文件,如果文件已存在,则删除其中全部数据,若文件不存在,则建立新文件。如已经使用ios::out方式打开,而未指定ios::appios::ateios::in,则同时默认此方式
ios::binary以二进制方式打开一个文件,如不指定此方式默认为ASCII方式
ios::nocreate打开一个已有的文件,如文件不存在,则打开失败。
ios::noreplace如果文件不存在则简历新文件,如果文件已存在则操作失败
ios::in | ios::out以输入和输出方式打开文件,文件可读可写
ios::out | ios::binary以二进制方式打开一个输出文件
ios::in | ios::binary以二进制方式打开一个输入文件

上面的输入输出方式设置可以使用位运算符中的或|进行组合。如果打开操作失败,open函数的返回值为假,如果是调用构造函数的方式打开文件,则流对象的值为0。

对文件读写操作完成后,应该关闭相关的文件。关闭用成员函数close完成。关闭就是解除改文件与文件流的关联,同样原来设置的工作方式也会失效,这样就不能再通过文件流对该文件进行输入和输出。

C++中对ASCII文件读写操作也可以使用左移或者右移运算符。<<表示刘插入运算符,而>>表示流提取运算符。这两用法和cin以及cout是一样的。在文件流中,常使用putgetgetline等成员函数进行字符的输入输出。put()输出单个字符,get()读取一个字符,getline()读取一行字符。

关于文件读写的示例代码如下。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <fstream>
#include <string>void test01()
{// 写文件 输出ofstream ofs("./test.txt", ios::out | ios::trunc);//ofs.open("./test.txt", ios::out | ios::trunc); 设置打开方式 以及路径if (!ofs.is_open()){cout << "文件打开失败" << endl;return;}ofs << "姓名:孙悟空" << endl;ofs << "年龄:999" << endl;ofs << "性别:女" << endl;// 关闭文件ofs.close();
}void test02()
{// 读文件ifstream ifs;ifs.open("./test.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, 1024))//{//	cout << buf << endl;//}// 第三种方式//string buf;//while (getline(ifs, buf))//{//	cout << buf << endl;//}// 第四种方式char c;while ((c = ifs.get()) != EOF){cout << c;}
}int main()
{test01();test02();system("pause");return 0;
}

相关文章:

C++核心编程 day09 类型转换、异常、输入输出流

C核心编程 day09 类型转换、异常、输入输出流 1. 类型转换2. 异常2.1 异常语法2.2 C标准异常库 3. 输入输出流3.1 输入输出流概念以及流类库3.2 标准输入流3.3 标准输出流3.4 文件读写 1. 类型转换 C中的类型转换有四类&#xff0c;分别是静态转换、动态转换、常量转换、重新解…...

Docker安装PostgreSQL

拉取镜像 docker pull postgres 运行容器 docker run --name postgres-db -e TZPRC -e POSTGRES_USERroot -e POSTGRES_DBdatabase -e POSTGRES_PASSWORD123456 -p 5432:5432 -v /Users/xiaoping/byx/postgresql/data:/var/lib/postgresql/data -d postgres run&#xff0c…...

py并发编程实践-demo

需求 已知条件&#xff1a;appX -请求-> api 多进程实现并发请求api 给定app应用列表&#xff0c;请求api核数 from datetime import datetime, timedelta from multiprocessing import Processclass ProcessTest(object):"""多进程并发请求API&#xff…...

1-2 暴力破解-模拟

模拟&#xff1a;根据题目要求编写代码 可分为&#xff1a;图形排版&#xff08;根据某种规则输出特定图形&#xff09;、日期问题、其他模拟 一.图形排版 1.输出梯形&#xff08;清华大学&#xff09; 法一&#xff1a;等差数列 分析&#xff1a;每行的星号个数为等差数列2n2…...

机器学习中的Bagging思想

Bagging&#xff08;Bootstrap Aggregating&#xff09;是机器学习中一种集成学习方法&#xff0c;旨在提高模型的准确性和稳定性。Bagging的思想源自于Bootstrap采样技术&#xff0c;其基本原理如下&#xff1a; Bootstrap采样&#xff1a; Bagging的核心思想是通过对原始数据…...

基于PyTorch搭建你的生成对抗性网络

前言 你听说过GANs吗&#xff1f;还是你才刚刚开始学&#xff1f;GANs是2014年由蒙特利尔大学的学生 Ian Goodfellow 博士首次提出的。GANs最常见的例子是生成图像。有一个网站包含了不存在的人的面孔&#xff0c;便是一个常见的GANs应用示例。也是我们将要在本文中进行分享的…...

ROS话题(Topic)通信:自定义msg - 例程与讲解

在 ROS 通信协议中&#xff0c;数据是以约定好的结构传输的&#xff0c;即数据类型&#xff0c;比如Topic使用的msg&#xff0c;Service使用的srv&#xff0c;ROS 中的 std_msgs 封装了一些原生的数据类型&#xff0c;比如&#xff1a;Bool、Char、Float32、Int64、String等&am…...

【Vue配置项】 computed计算属性 | watch侦听属性

目录 前言 computed计算属性 什么是计算属性&#xff1f; Vue的原有属性是什么&#xff1f; 得到的全新的属性是什么&#xff1f; 计算属性怎么用&#xff1f; 计算属性的作用是什么&#xff1f; 为什么说代码执行率高了&#xff1f; computed计算属性中的this指向 co…...

linux 查看命令使用说明

查看命令的使用说明的命令有三种&#xff0c;但并不是每个命令都可以使用这三种命令去查看某个命令的使用说明&#xff0c;如果一种不行就使用另外一种试一试。 1.whatis 命令 概括命令的作用 2.命令 --help 命令的使用格式和选项的作用 3.man 命令 命令的作用和选项的详细…...

ceph修复pg inconsistent( scrub errors)

异常情况 1、收到异常情况如下: OSD_SCRUB_ERRORS 12 scrub errors PG_DAMAGED Possible data damage: 1 pg inconsistentpg 6.d is activeremappedinconsistentbackfill_wait, acting [5,7,4]2、查看详细信息 登录后复制 #ceph health detail HEALTH_ERR 12 scrub errors…...

【论文精读】VOYAGER: An Open-Ended Embodied Agent with Large Language Models

Understanding LSTM Networks 前言Abstract1 Introduction2 Method2.1 Automatic Curriculum2.2 Skill Library2.3 Iterative Prompting Mechanism 3 Experiments3.1 Experimental Setup3.2 Baselines3.3 Evaluation Results3.4 Ablation Studies3.5 Multimodal Feedback from …...

Linux安装DMETL5与卸载

Linux安装DMETL5与卸载 环境介绍1 DM8数据库配置1.1 DM8数据库安装1.2 初始化达梦数据库1.3 创建DMETL使用的数据库用户 2 配置DMETL52.1 解压DMETL5安装包2.2 安装调度器2.3 安装执行器2.4 安装管理器2.5 启动dmetl5 调度器2.6 启动dmetl5 执行器2.7 启动dmetl5 管理器2.8 查看…...

Office Word 中的宏

Office Word 中的宏 简介宏的使用将自定义创建的宏放入文档标题栏中的“自定义快速访问工具栏”插入指定格式、内容的字符选中word中的指定文字查找word中的指定文字A&#xff0c;并替换为指定文字B插入文本框并向内插入文字word 表格中的宏操作遍历表格中的所有内容批量设置表…...

qt中d指针

在Qt中&#xff0c;d指针是一种常见的设计模式&#xff0c;也称为"PIMPL"&#xff08;Private Implementation&#xff09;或者"Opaque Pointer"。它主要用于隐藏类的实现细节&#xff0c;提供了一种封装和隔离的方式&#xff0c;以便在不影响公共接口的情…...

交易者最看重什么?anzo Capital这点最重要!

交易者最看重什么&#xff1f;有人会说技术&#xff0c;有人会说交易策略&#xff0c;有人会说盈利&#xff0c;但anzo Capital认为Vishal 最看重的应该是眼睛吧&#xff01; 29岁的Vishal Agraval在9年前因某种原因失去了视力&#xff0c;然而&#xff0c;他的失明并未能阻…...

window 搭建 MQTT 服务器并使用

1. 下载 安装 mosquitto 下载地址&#xff1a; http://mosquitto.org/files/binary/ win 使用 win32 看自己电脑下载相应版本&#xff1a; 一直安装&#xff1a; 记住安装路径&#xff1a;C:\Program Files\mosquitto 修改配置文件&#xff1a; allow_anonymous false 设置…...

Prometheus+Ansible+Consul实现服务发现

一、简介 1、Consul简介 Consul 是基于 GO 语言开发的开源工具&#xff0c;主要面向分布式&#xff0c;服务化的系统提供服务注册、服务发现和配置管理的功能。Consul 提供服务注册/发现、健康检查、Key/Value存储、多数据中心和分布式一致性保证等功能。 在没有使用 consul 服…...

【原创】java+swing+mysql校园活动管理系统设计与实现

前言&#xff1a; 本文介绍了一个校园活动管理系统的设计与实现。该系统基于JavaSwing技术&#xff0c;采用C/S架构&#xff0c;使用Java语言开发&#xff0c;以MySQL作为数据库。系统实现了活动发布、活动报名、活动列表查看等功能&#xff0c;方便了校园活动的发布和管理&am…...

vscode中vue项目引入的组件的颜色没区分解决办法

vscode中vue项目引入的组件的颜色没区分解决办法 图中引入组件和其他标签颜色一样没有区分&#xff0c;让开发者不易区分&#xff0c;很蓝瘦 这个就很直观&#xff0c;解决办法就是你当前的vscode版本不对&#xff0c;你得去找找其他版本&#xff0c;我的解决办法就是去官网历…...

uniapp: 实现pdf预览功能

目录 第一章 实现效果 第二章 了解并解决需求 2.1 了解需求 2.2 解决需求 2.2.1 方法一 2.2.2 方法二 第三章 资源下载 第一章 实现效果 第二章 了解并解决需求 2.1 了解需求 前端需要利用后端传的pdf临时路径实现H5端以及app端的pdf预览首先我们别像pc端一样&#…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

[特殊字符] Spring Boot底层原理深度解析与高级面试题精析

一、Spring Boot底层原理详解 Spring Boot的核心设计哲学是约定优于配置和自动装配&#xff0c;通过简化传统Spring应用的初始化和配置流程&#xff0c;显著提升开发效率。其底层原理可拆解为以下核心机制&#xff1a; 自动装配&#xff08;Auto-Configuration&#xff09; 核…...

C/Python/Go示例 | Socket Programing与RPC

Socket Programming介绍 Computer networking这个领域围绕着两台电脑或者同一台电脑内的不同进程之间的数据传输和信息交流&#xff0c;会涉及到许多有意思的话题&#xff0c;诸如怎么确保对方能收到信息&#xff0c;怎么应对数据丢失、被污染或者顺序混乱&#xff0c;怎么提高…...