c++文件操作

发布于:2025-07-10 ⋅ 阅读:(23) ⋅ 点赞:(0)

一、IO流简介

数据输入和输出过程也是数据传输的过程,数据就像流水一样从一个地方流动到另一个地方,因此,在c++中将此过程称为“流”

在c++的标准库中,将用于进行数据输入输出的类统称为“流类”。cin是流类istream的对象,cout是流类ostream的对象,要使用流类,需要在程序中包含iostream头文件

fstream最强大

cin是istrem的对象,cout是ostream的对象

上图中的箭头代表派⽣类。ios是抽象基类,它派⽣出istream和ostream。istream 和ostream⼜共同派⽣出了iostream类。 为了避免多继承的⼆义性,从ios派⽣出istream和ostream时,均使⽤virtual关键 字(虚继承)。 istream是⽤于输⼊的流类,cin就是该类的对象。 ostream是⽤于输出的流类,cout就是该类的对象。 ifstream是⽤于从⽂件读取数据的类。 ofstream是⽤于向⽂件写⼊数据的类。 iostream是既能⽤于输⼊,⼜能⽤于输出的类。 fstream是既能从⽂件读取数据,⼜能向⽂件写⼊数据的类

标准流对象

iostream头⽂件中定义了四个标准流对象,它们是cin、cout、cerr和clog。

cin对应于标准输⼊流,⽤于从键盘读取数据,也可以被重定向为从⽂件中读取数 据。

cout对应于标准输出流,⽤于向屏幕输出数据,也可以被重定向为向⽂件写⼊数 据。

clog对应于标准错误输出流,⽤于向屏幕输出错误信息,不能被重定向。

cerr和clog的区别在于:cerr不适⽤缓冲区,直接向显示器输出信息;⽽输出到 clog中的信息会先被存放到缓冲区,缓冲区满或者刷新时才输出到屏幕。

二、文件简介

1、文件名简介

一般是指内存以外的存储介质上的一批数据的集合。文件可以是一份报告,一张图片或者一个执行程序等数据格式

2、文件名组成

c++中的文件读取功能可以看出是数据流的源头,文件的写入就是数据流的终点。文件名标识文件,每一个文件都必须有代表他的文件名,文件名分为主文件名和扩展名,中间以点号分割

3、文件的分类

文件按照存储的种类可以分为:文本文件、二进制文件

文本文件是以字符编码的方式进行存储

二进制文件是以二进制格式存储,将内存中的数据原封不动的存储到文件中,适合于非字符为主的数据,如果用记事本打开这类文件,我们就会看到一堆乱码

三、文件操作的步骤

1、定义一个文件对象

ifstream 文件只做读操作

ofstream 文件只做写操作

fstream 文件可读可写

2、打开文件(文件对象与磁盘之间的联系,映射)

创建⽂件对象后就可以使⽤open成员函数打开⽂件对象。 语法格式为: open("⽂件名或完整路径") 或者 open("⽂件名或完整路径",ios::打开模式) ⽂件的打开模式是以下标志符的⼀个组合: in : 只读模式打开,⽂件不存在就报错 out :只写模式打开,覆盖存在的内容,⽂件不在则创建 app :以附加模式打开,从⽂件末尾写⼊,⽂件不存在则创建⼀个 ate:打开⽂件并移动⽂件指针到⽂件末尾处 trunc: 以只写模式打开⽂件,若⽂件存在则删除该⽂件再新建⼀个 binary 以⼆进 制模式打开⽂件每⼀种打开⽅式是以⼆进制位来表示的,因此可以使⽤⼆进制的或 运算符(|),将⼏种模式组合起来。⽐如 ios::in|ios:binary 打开⼀个⼆进制⽂件 并⽤于输⼊。 不同类的默认打开模式说明:

3、对文件进行读写

4、使用成员函数关闭打开的文件

文件的打开与关闭

创建⽂件对象后就可以使⽤open成员函数打开⽂件对象。 语法格式为: open("⽂件名或完整路径") 或者 open("⽂件名或完整路径",ios::打开模式) ⽂件的打开模式是以下标志符的⼀个组合:

in : 只读模式打开,⽂件不存在就报错

out :只写模式打开,覆盖存在的内容,⽂件不在则创建

app :以附加模式打开,从⽂件末尾写⼊,⽂件不存在则创建⼀个

ate:打开⽂件并移动⽂件指针到⽂件末尾处

trunc: 以只写模式打开⽂件,若⽂件存在则删除该⽂件再新建⼀个 binary 以⼆进 制模式打开⽂件每⼀种打开⽅式是以⼆进制位来表示的,因此可以使⽤⼆进制的或 运算符(|),将⼏种模式组合起来。⽐如 ios::in|ios:binary 打开⼀个⼆进制⽂件 并⽤于输⼊。

#include <iostream>
#include <string>
#include<fstream>//string.h
using namespace std;//cout cin   std::cout std::cin

//https://cplusplus.com/reference查看c语言和c++的各种库



int main()
{

    fstream file;
    //void open (const char* filename,           ios_base::openmode mode = ios_base::in | ios_base::out);
    file.open("d:\\laowang.txt", ios::in);//打开文件
    //bool is_open() const;
    if (file.is_open())
        cout << "file open sucessed\n" << endl;
    else
      cout << "file open failed\n" << endl;

    //istream& read (char* s, streamsize n);
    //按指定数量的字符进行读取
    char buff[100] = { 0 };
   // file.read(buff,100);//如果文件的内容小于指定 读取数量则按文件的实际字符数量进行读取
    

    //istream& get(char& c); bool eof() const;
    //char mychar;
    //while (file.eof() != true) //通过eof方法检测是否到达文件的结尾,到达则返回true
    //{
    //    file.get(mychar);//按字符读取
    //    cout << mychar;
    //}

    //按行读取
    //istream& getline (char* s, streamsize n );
    while (file.eof() != true)
    {
        memset(buff, 100, 0);
        file.getline(buff, 100);
        cout << buff;
    }

    file.close();//文件的关闭函数

  //  cout << buff << endl;
}

5、文件的打开与写入

类ofstream, ifstream 和fstream 是分别从ostream, istream 和iostream 中继承 ⽽来的 因此 fstream 的对象可以使⽤其⽗类的成员那样使⽤>运算符来操作数据。 ⽂件的写⼊操作: ⼀次写⼊⼀个字符:⽂件对象.put(char ch) 写⼊多个字符的格式为:⽂件对象<<写⼊数据

⽂件的读取操作: 读取⽂件可以使⽤提取运算符“>>”,通过该运算符可以从⽂件中的数据传到程序 中,⽤法和cin⼀样。 语法格式为:⽂件对象>>读取数据; 另外C++也提供了两个函数来读取⽂件: get( char ch):从⽂件⼀次读取⼀个字符并存⼊ch中 geiline(char*str,int size):从⽂件中⼀次读取⼀⾏字符串,直到遇到“\n”结束, size为字符串str的⼤⼩。 对于如何判断⽂件读取完成,可以通过eof()判断⽂件是否读到⽂件的末尾,如果读 ⽂件到达⽂件末尾,返回true。

6、二进制文件的读写

二进制虽然不能通过一般文本编辑器查看,但是他具有访问速度快,占用空间小以及可以随机存取数据的优点。

⼆进制⽂件的写⼊不能使⽤插⼊运算符实现写⼊。

写⼊变量⽐如整数,浮点数,字符串还是⼀个数据结构都可以,在⽂件打开模式需 要设置为binary。

写⼊语法格式为:

⽂件对象.write((char*)&写⼊变量,sizeof(写⼊变量));

读取语法格式为:

⽂件对象.read((char*)&写⼊变量,sizeof(写⼊变量));

int main()
{

    fstream file1,file2;
    file1.open("D:\\共享文件夹\\2502\\day10\\截图03.png", ios::in|ios::binary );
    if (file1.is_open())
    {
        cout << "file1 sucessed\n" << endl;
    }
    else
    {
        cout << "file1 failed\n" << endl;
        return -1;
    }
 
    char* pt = new char[40846];
    file1.read(pt, 40846);
  

    file1.close();

    file2.open("d:\\jiayi.png", ios::out| ios::binary);
    if (file2.is_open())
    {
        cout << "file2 sucessed\n" << endl;
    }
    else
    {
        cout << "file2 failed\n" << endl;
        return -1;
    }
    file2.write(pt, 40846);
    file2.close();

    delete[] pt;
}

⽂件的随机访问: 在⽂件的信息区中存在⼀个⽤于指示当前⽂件读取位置的指针变量称为⽂件定位指 针,C++语⾔允许从⽂件中信息的先后来进⾏读写,同时也允许从⽂件的任何位置 开始对⽂件进⾏读写操作,这种读写⽅式称为⽂件的随机访问。 

C++中的ifstream和ofstream类分别提供了⼏个⽀持⽂件随机访问的函数。

Seekg(long streamoff,seekdir)

将⽂件的定位指针按seek_dir确定的⽅向移动streamoff位置。

Seekdir:

ios::beg 枚举常量为0, ⽂件开头Ios:cur 枚举常量为1

⽂件的当前位置Ios::end 枚举常量为2 ⽂件末尾

Tellg() :返回输⼊⽂件中 ⽂件定位指针的当前位置

int main()
{

    fstream file1,file2;
    file1.open("D:\\laowang.txt", ios::in );
    if (file1.is_open())
    {
        cout << "file1 sucessed\n" << endl;
    }
    else
    {
        cout << "file1 failed\n" << endl;
        return -1;
    }
    char buff[100] = { 0 };
    file1.seekg(4,ios::beg);//游标调整,决定了文件读写的位置
    cout << "current pos=" << file1.tellg() << endl;//获取文件游标的位置
    file1.getline(buff,100);
  

    file1.close();
    cout << buff << endl;
}

四、c++异常处理

1、异常

程序运行时发生的反常行为,这些行为超出了函数正常功能的范围,例如运行时耗尽了内存或遇到意外的非法输入。异常存在于程序的正常功能之外,并要求程序立即处理,不做异常处理会导致程序的中断,当程序的某部分检测到一个它无法处理的问题时,需要用到异常处理。异常提供了一种转移程序控制权的方式。C++异常处理涉及到三个关键字:try、catch、throw。

try、catch语句的语法如下

try、catch 语句的语法如下:
try{
//Code that may generate exceptions
}catch(type1 id1){
//Handle exceptions of type1
}catch(type2 id2){
//Handle exceptions of type2
}
//(以下为不完整内容)
}catch(tvpe3 id3){
}
int main()
{
    try{//try语句块中 放可能出错的代码块
        cout << "please input two numbers:";
        int num1, num2;
        cin >> num1 >> num2;
        if (num2 == 0)//一旦抛出异常,异常后的代码不会得到执行
            throw 1.1;//c++中,提供了一个关键字throw 用于用户实现主动抛出异常
        int ret = num1 / num2;
        cout << "result=" << ret << endl;
    }//如果捕获到异常,执行对应的catch分支,执行完就会跳出整个try。。。catch结构
    catch (int msg) //通过catch关键字来捕获整数类型的异常
    {
        cout << "捕获到整数类型的异常" << msg << endl;
    } //如果系统抛出的异常 没有被catch子句捕获到,则系统会自动调用abort函数杀死当前的程序


    cout << "end" << endl;

    return 0;
}
int main()
{
    try{//try语句块中 放可能出错的代码块
        cout << "please input two numbers:";
        int num1, num2;
        cin >> num1 >> num2;
        if (num2 == 0)
            throw 1.1;//异常的抛出可以主动抛,也可以被动抛
        int ret = num1 / num2;
        cout << "result=" << ret << endl;
    }
    catch (int msg) //在异常的不捕获语法中,一个try至少要对应一个catch,也可以对应多个catch
    {
        cout << "捕获到整数类型的异常" << msg << endl;
    }
    catch (string  msg)//出现异常,会从上往下依次比对CATCH的捕获类型与抛出类型去比对
    {                             //如果比对成功则执行对应catch的分支 分支执行完则跳出整个异常语法结构
        cout << "捕获到string类型的异常" << msg << endl;
    }
    catch (double  msg) //如果说所有的catch都没有捕获到异常类型,则系统调用abort来终止当前的程序
    {
        cout << "捕获到double类型的异常" << msg << endl;
    }


    cout << "end" << endl;
    //对于异常嵌套的场景,如果内层出现异常,先尝试用内层去捕获,如果捕获不到,该异常会上抛到外层去处理
    //如果内层捕获到了异常,但是处理可能不够完善,可以执行throw子句继续将该异常上抛,希望在外层得到妥善处理
    return 0;
}
//please input two numbers : 12 0
//捕获到整数类型的异常1
//end

2、万能捕获(捕获所有异常)

万能的错误类型捕获,用...表示

catch(...)

{

}

void test()throw(int, double);//异常的接口声明
void test()
{
    int num1;
    cin >> num1;
    if (num1 > 10)
        throw 1;
    else
        throw 1.1;

}

int main()
{
    try{//try语句块中 放可能出错的代码块
        cout << "please input two numbers:";
        int num1, num2;
        cin >> num1 >> num2;
        if (num2 == 0)
            throw 1.1;//异常的抛出可以主动抛,也可以被动抛
        int ret = num1 / num2;
        cout << "result=" << ret << endl;
    }
    catch (int msg) //在异常的不捕获语法中,一个try至少要对应一个catch,也可以对应多个catch
    {
        cout << "捕获到整数类型的异常" << msg << endl;
    }
    catch (...)//万能捕获后 不要在家任何的catch子句  可以捕获任何类型的异常
    {                             
        cout << "万能捕获" << endl;
    }
  


    cout << "end" << endl;
  
    return 0;
}

3、异常处理接口声明

  1. 核心目的: 为方便程序员阅读代码,提高程序可读性。

  2. 具体做法: 将函数中的异常类型声明至函数头后方,避免逐行查找函数内的异常抛出内容。

  3. 语法标准: 该写法属于C++标准语法

  4. 兼容性说明: 在Visual Studio(VS)老版本中,此操作不被支持,会抛出编译警告

4、标准异常

标准异常的基类

C++标准库提供的一系列标准异常,均从 exception派生而来。

两大核心派生类

标准异常主要分为两类,均定义在 <stdexcept> 头文件中:

  • logic_error(逻辑错误类): 描述程序中可预知的逻辑错误(如传递无效参数),属于编程逻辑漏洞导致的错误。
  • runtime_error(运行时错误类): 描述无法预料的外部事件导致的错误(如硬件故障、内存耗尽),属于程序运行时无法控制的异常。

 异常信息的处理

  • 构造函数logic_error 和 runtime_error 均提供 std::string 参数的构造函数,用于保存具体的异常信息(如“无效参数”“内存耗尽”)。
  • 信息获取:通过 what() 成员函数what 函数名被红笔标注)获取保存的异常信息(例如 e.what() 会返回构造时传入的字符串)。

bad_alloc

  • 触发场景:使用 new 运算符进行动态内存分配时,若系统没有足够的内存满足分配请求,则会抛出此异常。

out_of_range

  • 触发场景:当访问**vectorstring容器的at() 方法**时,若索引超出容器的有效范围(如索引小于0或大于等于容器大小),会引发此异常。

 bad_typeid

  • 说明:使用typeid操作一个NULL指针,而且该指针是带有虚函数的类,这时抛出

typeid是操作符,不是函数。这点与sizeof类似,运行时获知变量类型名称,可以使用typeid(变量).name(),需要注意不是所有的编译器可以这样使用。

#include <iostream>
#include <string>
#include<fstream>//string.h
using namespace std;//cout cin   std::cout std::cin


int main()
{
    string str = "hello";
    try
    {
        cout << str.at(10000);
    }
    catch (out_of_range e)
    {   
        cout << "检测到越界" << endl;
    }
    //try {

    //    double* pt = new double[0xfffffff];//通过异常处理机制来检测对内存的申请 有没有成功

    //}
    //catch (bad_alloc e)
    //{
    //    cout << "对内存分配失败" << endl;
    //}

    //cout << "end" << endl;

    return 0;
}

案例题

用户从键盘输入形式如#ab!#12-45*c*#+*f*这样的"数值范围"字符串,代表从12到45这个范围。12前面和45后面会有一些不包含数字以及英文连字符的干扰字符。请你编写一个类Parse,可以解析这个字符串。然后提供两个函数,能够获取字符串中的第一个整数和第二个整数。

class  Parse
{
public:
    string str;
    int index;
    Parse(string str)
    {
        this->str = str;
        index = 0;
    }

    int extract_firstString()//#ab!#12-45*c*#+*f*
    {
        index = 0;
       string temp = "";
       for (int i = 0; str.at(i) != '-'; i++)
       {
           if (str.at(i) >= '0' && str.at(i) <= '9')
           {
               temp = temp + str.at(i);
           }
           index++;

       }

      return  std::stoi(temp);
    }

    int extract_secondString()
    {
        string temp = "";
        int str_size = str.size();
        for (int i = index; i < str_size; i++)
        {
            if (str.at(i) >= '0' && str.at(i) <= '9')
            {
                temp = temp + str.at(i);
            }

        }
        return  std::stoi(temp);

    }

};

int main()
{
   
    Parse p_str("#ab!#12-45*c*#+*f*");
    cout << p_str.extract_firstString() << endl;
    cout << p_str.extract_secondString()<< endl;

    cout << p_str.extract_firstString() << endl;
    cout << p_str.extract_secondString() << endl;
    return 0;
}


网站公告

今日签到

点亮在社区的每一天
去签到