C++异常处理

来源:互联网 发布:dvd自动播放软件 编辑:程序博客网 时间:2024/06/16 16:00

一、类型转换

#include <stdio.h>/*static_cast      用来普通类型之间的转换reinterpret_cast 用来进行指针之间的转换dynamic_cast     用在层次关系中的转换,在运行时进行类型识别,进行基类与派生类之间的转换const_cast       用来去掉只读属性*/// 基类:抽象类class Animal{public:    virtual void speak() = 0;};class Dog:public Animal{public:    virtual void speak()    {        printf ("狗 汪汪\n");    }    void lookHome()    {        printf ("狗 在 看家\n");    }};class Cat:public Animal{public:    virtual void speak()    {        printf ("猫 喵喵\n");    }    void Cute()    {        printf ("猫 在家 卖萌\n");    }};class Student{};void print(const char *str){    // const char *str 修饰 * 不能通过该指针改变指向的地方    // str[2] = 'w';    // char *p = str;    // 去掉 const 只读属性,进行强制转换    char *p = const_cast<char *>(str);    // str[2] = '2';    p[2] = 'w';    printf ("str = %s\n", str);}int main(){    // char str[] = "hello world";    // print(str);    // "hello world" 是常量,常量值是不能改变的    char *str = "hello world";  //  print(str);    char *str1[] = {"123", "daa", "wq111"};    str1[0][2] = '3';    return 0;}void func(Animal *p){    // 多态:继承、虚函数、基类指针指向派生类    p->speak();    // 想识别 这个 p 的类型    // 运行时进行类型识别(RTTI),做的是强制转换    // 如果类型匹配,转换成功    // 如果类型不匹配,转换失败,失败返回 NULL    // 把基类指针转换为派生类指针    Dog *pd = dynamic_cast<Dog*>(p);    if (pd != NULL)    {        pd->lookHome();    }    Cat *pc = dynamic_cast<Cat *>(p);    if (pc != NULL)    {        pc->Cute();    }}int main1_3(){    Dog d;    Cat c;    func(&d);    func(&c);    return 0;}int main1_2(){    Animal *pa = NULL;    Dog d;    Cat c;    pa = &d;    // 凡是可以隐式转换的地方都可以用 static_cast    pa = static_cast<Animal *>(&c);      {        // Student *s1 = static_cast<Student *>(&c);          Student *s1 = reinterpret_cast<Student*>(&c);    }    return 0;}int main1_1(){    int a = 10;    double d= 1.2;    // a = d;              // 隐式转换    char ch = (char)d;  // 强制转换    // 普通类型之间的转换:凡是可以隐式转换的地方,都可以用 static_cast    // 在编译期间进行类型识别    a = static_cast<int>(d);     double *pd = &d;    // int    *pa = static_cast<int*>(pd);          // 不能做不同类型指针之间的转换    int *pa = reinterpret_cast<int *>(pd);          // 用来做指针之间的转换    int *p1 = reinterpret_cast<int *>(0x12345678);  // 可以用来在整形与指针之间进行转换    // 可以隐式转换的地方用  static_cast    // 需要指针强制转换的地方 用 reinterpret_cast    return 0;}

二、异常处理

1. 什么是异常

1)异常是一种程序控制机制,与函数机制独立和互补

函数是一种以栈结构展开的上下函数衔接的程序控制系统,异常是另一种控制结构,它依附于栈结构,却可以同时设置多个异常类型作为网捕条件,从而以类型匹配在栈机制中跳跃回馈.

2)异常设计目的:

栈机制是一种高度节律性控制机制,面向对象编程却要求对象之间有方向、有目的的控制传动,从一开始,异常就是冲着改变程序控制结构,以适应面向对象程序更有效地工作这个主题,而不是仅为了进行错误处理。
异常设计出来之后,却发现在错误处理方面获得了最大的好处。

2. 异常的基本语法

这里写图片描述

1) 若有异常则通过throw操作创建一个异常对象并抛掷。
2) 将可能抛出异常的程序段嵌在try块之中。控制通过正常的顺序执行到达try语句,然后执行try块内的保护段。
3) 如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行。程序从try块后跟随的最后一个catch子句后面的语句继续执行下去。
4) catch子句按其在try块后出现的顺序被检查。匹配的catch子句将捕获并处理异常(或继续抛掷异常)。
5) 如果匹配的处理器未找到,则运行函数terminate将被自动调用,其缺省功能是调用abort终止程序。
6)处理不了的异常,可以在catch的最后一个分支,使用throw语法,向上扔。
7)异常机制与函数机制互不干涉,但捕捉的方式是基于类型匹配。捕捉相当于函数返回类型的匹配,而不是函数参数的匹配,所以捕捉不用考虑一个抛掷中的多种数据类型匹配问题
8)异常捕捉严格按照类型匹配
异常捕捉的类型匹配之苛刻程度可以和模板的类型匹配媲美,它不允许相容类型的隐式转换,比如,抛掷char类型用int型就捕捉不到

构造函数没有返回类型,无法通过返回值来报告运行状态,所以只通过一种非函数机制的途径,即异常机制,来解决构造函数的出错问题。

3. 异常处理的基本语法

这里写图片描述

1)C++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理。上层调用者可以再适当的位置设计对不同类型异常的处理。
2)异常是专门针对抽象编程中的一系列错误处理的,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法进行跳跃,但错误处理的特征却是遇到错误信息就想要转到若干级之上进行重新尝试,如图
这里写图片描述
3)异常超脱于函数机制,决定了其对函数的跨越式回跳。
4)异常跨越函数

#include <stdio.h>// 1、可能发生异常的代码要放到 try块里,异常是需要人为抛的 通过 throw// 2、异常是跨函数的// 3、捕获到异常:1、处理它 不让它继续向上抛  2、不处理,继续向上抛// 4、catch 去进行异常捕捉的时候,要严格遵循类型匹配,和 模板的类型匹配程序相同,不允许做类型的隐式转换int main(){    try    {        // throw 10;        throw 'a';    }    catch (int e)    {        printf ("捕获  int 异常\n");    }    catch (...)    {        printf ("捕获其他异常\n");    }    return 0;}void divid(int x, int y){    if (y == 0)    {        //  return;        throw x;   // 抛出一个异常,类似与 return 返回值    }    printf ("%d / %d = %d\n", x, y, x/y);}void func(){    divid(10,0);    printf ("func 函数调用\n");}void func1(){    try    {        divid(10,0);    }    catch (int e)    {        // printf ("func1 处理了异常:%d 整除 0\n", e);        printf ("func1 捕获了异常, 不高兴处理了\n");        throw;  // 不处理的情况下,一定要调用 throw 向上抛    }    catch (...)    {        printf ("其他类型异常\n");    }    printf ("111111111111111111111\n");}int main2_2(){    try    {        // func ();        func1();    }    catch (int e)    {        printf ("捕获一个异常:%d 整除 0\n", e);    }    catch (...)    {        printf ("其他类型异常\n");    }    return 0;}int main2_1(){    divid (10, 2);    // 把可能发生错误的代码放到 try 语句块中    // try 不是用处理错误,用来处理异常     // 异常是需要人为 抛 的    divid (10,0);    try    {        divid (10,0);    }    catch (int e)    {        printf ("捕获一个异常:%d 整除 0\n", e);    }    catch (...)    {        printf ("其他类型异常\n");    }    return 0;}

4.栈解旋 和 异常接口声明

  • 栈解旋

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

  • 异常接口声明

1)为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型,例如:
void func() throw (A, B, C , D); //这个函数func()能够且只能抛出类型A B C D及其子类型的异常。
2)如果在函数声明中没有包含异常接口声明,则次函数可以抛掷任何类型的异常,例如:
void func();
3)一个不抛掷任何类型异常的函数可以声明为:
void func() throw();
4) 如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexpected函数会被调用,该函数默认行为调用terminate函数中止程序。

#include <stdio.h>class A{public:    A(int a, int b)    {        this->a = a;        this->b = b;        printf ("A 的构造, a = %d, b = %d\n", a , b);    }    ~A()    {        printf ("A 的析构, a = %d, b = %d\n", a, b);    }private:    int a;    int b;};// 栈上的变量:在 try到 throw 创建的对象会自动释放  栈解旋// 堆上的对象:当发生异常的时候,堆上的对象不会自动释放void func1(){    A b (3, 4);    A c (5,6);    // 堆上的对象需要自己管理,当发生异常的时候,堆上的对象不会自动释放    A *pd = new A(7,8);    throw 10;    printf ("222222222222222222222\n");}void func(){    A a(1,2);    func1();    printf ("1111111111111111111111\n");}int main3_1(){    try    {        func();    }    catch (int e)    {        printf ("捕获一个异常\n");        }    return 0;}// 异常接口// 默认的函数可以抛出任意类型的异常void func3_1(){    // throw 1;    throw 'a';}// 只能抛出 int 型异常void func3_2() throw (int){}// 只能抛出 int  char  char *类型的异常void func3_3() throw (int, char, char*){}// 函数不能抛出任何异常void func3_4() throw (){}int main(){    return 0;}

5. 异常类型和变量的生命周期

  • throw的异常是有类型的,可以是,数字、字符串、类对象。
  • throw的异常是有类型的,catch严格按照类型进行匹配。
  • -

注意 异常对象的内存模型 。

#include <stdio.h>#include <string.h>int myStrcpy(char *dst, const char *src){    if (dst == NULL)        return 1;    if (src == NULL)        return 2;    if (strcmp(src,"end") == 0)        return 3;    while (*src != '\0')    {        *dst = *src;        dst++;        src++;    }    *dst = '\0';    return 0;}int myStrcpy1(char *dst, const char *src){    if (dst == NULL)        throw 1;    if (src == NULL)        throw 2;    if (strcmp(src,"end") == 0)        throw 3;    while (*src != '\0')    {        *dst = *src;        dst++;        src++;    }    *dst = '\0';    return 0;}int myStrcpy2(char *dst, const char *src){    if (dst == NULL)        throw "目的字符串出错";    if (src == NULL)        throw "源字符串出错";    if (strcmp(src,"end") == 0)        throw "不能拷贝的字符串";    while (*src != '\0')    {        *dst = *src;        dst++;        src++;    }    *dst = '\0';    return 0;}class Error1{public:    Error1(int a)    {        this->a = a;        printf ("构造函数: %d\n", a);    }    Error1(const Error1 &obj)    {        static int b = 0;        b++;        a = obj.a + b;        printf ("拷贝构造函数: %d\n", a);    }    ~Error1()    {        printf ("析构函数: %d\n", a);    }private:    int a;};class Error2{};class Error3{};// 抛一个 对象// 1、拿一个普通变量去收,会有匿名对象产生,但是这个匿名对象生命周期持续到异常处理结束// 2、拿引用接,会直接引用这个匿名对象,不会产生多个备份// 3、去接一个对象指针,如果这个对象是在栈上,在异常接收之前,这个对象就释放掉了// 接回来的指针不能再使用,是一个非法的指针// 4、去接一个堆上的对象指针,该对象不会自动释放,需要手动调用delete去释放//catch 的类型: 引用 和 普通变量不能共存、 引用 和 指针可以共存int main(){    try    {        // Error1 a(1);        // throw a;        // throw Error1(1);    // 会产生一个匿名对象,这个匿名对象生命周期延续到异常处理结束        // throw &Error1(1);        throw new Error1(1);    }    //catch (Error1 e) // { //     printf ("Error1 异常\n"); // }    catch (Error1& e)    {        printf ("Error1 异常\n");    }    catch (Error1* e)    {        printf ("Error1 异常\n");        delete e;  // 如果是堆上的指针,需要手动调用 delete 去释放     }    catch (Error2 &e)    {        printf ("Error2 异常\n");    }    catch (Error3 &e)    {        printf ("Error3 异常\n");    }    catch (...)    {        printf ("捕获一个其他异常\n");    }    return 0;}// 抛 int 类型异常int main4_2(){    try    {        char *src = "end";        char dst[100];        myStrcpy2(dst, src);        // myStrcpy1(dst, src);    }    catch (int e)    {        switch (e)        {        case 1:            printf ("目的字符串出错\n");            break;        case 2:            printf ("源字符串出错\n");            break;        case 3:            printf ("不能拷贝的字符串\n");            break;        }    }    catch (char *e)    {        printf ("捕获到一个异常:%s\n", e);    }    catch (...)    {        printf ("捕获其他类型异常\n");    }    return 0;}int main4_1(){    char *src = "end";    char dst[100];    int ret = myStrcpy(dst, src);    switch (ret)    {    case 1:        printf ("目的字符串出错\n");        break;    case 2:        printf ("源字符串出错\n");        break;    case 3:        printf ("不能拷贝的字符串\n");        break;    }    return 0;}

6. 异常在类层次中使用

  • 异常是类 – 创建自己的异常类
  • 异常派生
  • 异常中的数据:数据成员
  • 按引用传递异常
    • 在异常中使用虚函数

案例:设计一个数组类 MyArray,重载[]操作,
数组初始化时,对数组的个数进行有效检查
1)index<0 抛出异常eNegative
2)index = 0 抛出异常 eZero
3)index>1000抛出异常eTooBig
4)index<10 抛出异常eTooSmall
5)eSize类是以上类的父类,实现有参数构造、并定义virtual void printErr()输出错误。

#include <stdio.h>/*案例:设计一个数组类 MyArray,重载[]操作,    数组初始化时,对数组的个数进行有效检查     index<0 抛出异常eNegative      index = 0 抛出异常 eZero      3)index>1000抛出异常eTooBig     4)index<10 抛出异常eTooSmall     5)eSize类是以上类的父类,实现有参数构造、并定义virtual void printErr()输出错误。*/class MyArray{public:    MyArray (int len);    ~MyArray();    int &operator[](int index);    // 相关的错误处理类,都继承 eSize:内部类    class eSize    {    public:        eSize(int size)        {            this->size = size;        }        virtual void printErr() = 0;    protected:        int size;    };    class eNegative:public eSize    {    public:        eNegative(int len):eSize(len)        {        }        virtual void printErr()        {            printf ("数组长度小于0: %d\n", size);        }    };    class eZero:public eSize    {    public:        eZero(int len):eSize(len)        {        }        virtual void printErr()        {            printf ("数组长度等于0: %d\n", size);        }    };    class eTooBig:public eSize    {    public:        eTooBig(int len):eSize(len)        {        }        virtual void printErr()        {            printf ("数组长度大于1000: %d\n", size);        }    };    class eTooSmall:public eSize    {    public:        eTooSmall(int len):eSize(len)        {        }        virtual void printErr()        {            printf ("数组长度小于10: %d\n", size);        }    };private:    int len;    int *m_p;};MyArray::MyArray(int len){    if (len < 0)        throw eNegative(len);    if (len == 0)        throw eZero(len);    if (len > 1000)        throw eTooBig(len);    if (len < 10)        throw eTooSmall(len);    this->len = len;    m_p = new int[len];}MyArray::~MyArray(){    if(m_p != NULL)        delete [] m_p;    m_p = NULL;    len = 0;}int &MyArray::operator[](int index){    return m_p[index];}   int main(){    try    {        // MyArray a(-10);        // MyArray a(0);        // MyArray a(2000);        MyArray a(5);        for (int i = 0; i < 10; i++)        {            a[i] = i;        }    }    catch (MyArray::eSize &e)   // 多态    {        // printErr是虚函数  e 是基类的引用,可以发生多态        e.printErr();    }    catch(...)    {        printf ("捕获其他异常\n");    }    return 0;}int main1(){    try    {        // MyArray a(-10);        // MyArray a(0);        // MyArray a(2000);        MyArray a(5);        for (int i = 0; i < 10; i++)        {            a[i] = i;        }    }    catch (MyArray::eNegative &e)    {        e.printErr();    }    catch (MyArray::eZero &e)    {        e.printErr();    }    catch (MyArray::eTooBig &e)    {        e.printErr();    }    catch (MyArray::eTooSmall &e)    {        e.printErr();    }    catch(...)    {        printf ("捕获其他异常\n");    }    return 0;}

7. 标准程序库异常

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

#include <stdio.h>#include <stdexcept>#include <typeinfo>#include <iostream>class Student{public:    Student (int age)    {        if (age > 200)            throw std::out_of_range("年龄太大");        this->age = age;    }private:    int age;};// 自己的异常类class MyException:public std::exception{public:    MyException (char *msg)    {        strcpy (this->msg, msg);    }public:      virtual const char * what() const      {          return msg;      }private:    char msg[20];};// 使用标准异常库 提供的 异常类int main(){    try    {        // Student s1(300);        // throw MyException("我的异常类");        char *p = nullptr;        MyException *p1 = new MyException("adss");        Student *p2 = dynamic_cast<Student*>(p1);    }    catch (std::exception &e)    {        printf ("捕获一个异常: %s\n", e.what());    }    return 0;}

三、文件操作

I/O流概念和流类库结构

与iostream类库有关的头文件

iostream类库中不同的类的声明被放在不同的头文件中,用户在自己的程序中用#include命令包含了有关的头文件就相当于在本程序中声明了所需 要用到的类。可以换 —种说法:头文件是程序与类库的接口,iostream类库的接口分别由不同的头文件来实现。常用的有

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

在iostream头文件中定义的流对象

在 iostream 头文件中定义的类有 ios,istream,ostream,iostream,istream _withassign, ostream_withassign,iostream_withassign 等。

在iostream头文件中不仅定义了有关的类,还定义了4种流对象,
这里写图片描述
在iostream头文件中定义以上4个流对象用以下的形式(以cout为例):
ostream cout ( stdout);
在定义cout为ostream流类对象时,把标准输出设备stdout作为参数,这样它就与标准输出设备(显示器)联系起来,如果有
cout <<3;
就会在显示器的屏幕上输出3。

在iostream头文件中重载运算符

“<<”和“>>”本来在C++中是被定义为左位移运算符和右位移运算符的,由于在iostream头文件中对它们进行了重载, 使它们能用作标准类型数据的输入和输出运算符。所以,在用它们的程序中必须用#include命令把iostream包含到程序中。

#include <iostream>>>a表示将数据放入a对象中。<<a表示将a对象中存储的数据拿出。

标准I/O流

标准输入流

标准输入流对象cin,重点掌握的函数

  • cin.get() //一次只能读取一个字符 遇到EOF结束
  • cin.get(一个参数) //读一个字符
  • cin.get(三个参数) //可以读字符串
  • cin.getline()
  • cin.ignore()
  • cin.peek()
  • cin.putback()
#include <iostream>using namespace std;/*cin.get() //一次只能读取一个字符  遇到EOF结束cin.get(一个参数) //读一个字符cin.get(三个参数) //可以读字符串cin.getline()cin.ignore()cin.peek()cin.putback()*/int main1(){    char ch;    char ch1;    char ch2;    // cin >> ch;    // ch = cin.get();   // getchar()    // cin.get(ch);    // cin.get(ch).get(ch1).get(ch2);    // cin >> ch >> ch1 >> ch2;    // cout << ch << " " << ch1 << " " << ch2<<  endl;    // EOF  ==== Ctrl + Z    while ((ch = cin.get()) != EOF)    {        cout << ch;    }    return 0;}int main2(){    char str[100];    cin >> str;           // cin 同样读不了空格    // cin.getline(str, 100);   // fgets    cin.ignore(3);    cin >> str;    cout << str << endl;    return 0;}int main3(){    char ch;    char str[100];    // cin >> ch;    // 偷窥一下 缓冲区里面数据,读一个字符的数据,但是不从缓冲区移除    ch = cin.peek();       cout << ch << endl;    cin >> str;    cout << str << endl;    return 0;}int main(){    char ch;    char str[100];    cin >> ch;    cin.putback(ch);    cin >> str;    cout << str << endl;    return 0;}

标准输出流
标准输出流对象cout

  • cout.flush()
  • cout.put()
  • cout.write()
  • cout.width()
  • cout.fill()
  • cout.setf(标记)
manipulator(操作符、控制符)flushendloctdechexsetbasesetwsetfillsetprecision

C++格式化输出,C++输出格式控制

在输出数据时,为简便起见,往往不指定输出的格式,由系统根据数据的类型采取默认的格式,但有时希望数据按指定的格式输出,如要求以十六进制或八进制形式 输出一个 整数,对输出的小数只保留两位小数等。有两种方法可以达到此目的。
1)使用控制符的方法;
2)使用流对象的有关成员函数。

文件I/O

文件流类和文件流对象

输入输出是以系统指定的标准设备(输入设备为键盘,输出设备为显示器)为对象的。在实际应用中,常以磁盘文件作为对象。即从磁盘文件读取数据,将数据输出到磁盘文件。
和文件有关系的输入输出类主要在fstream.h这个头文件中被定义,在这个头文件中主要被定义了三个类,由这三个类控制对文件的各种输入输出操 作,他们分别是ifstream、ofstream、fstream,其中fstream类是由iostream类派生而来,他们之间的继承关系见下图所 示。
这里写图片描述
输入输出是以系统指定的标准设备(输入设备为键盘,输出设备为显示器)为对象的。在实际应用中,常以磁盘文件作为对象。即从磁盘文件读取数据,将数据输出到磁盘文件。
和文件有关系的输入输出类主要在fstream.h这个头文件中被定义,在这个头文件中主要被定义了三个类,由这三个类控制对文件的各种输入输出操 作,他们分别是ifstream、ofstream、fstream,其中fstream类是由iostream类派生而来,他们之间的继承关系见下图所 示。

文件流的打开
所谓打开(open)文件是一种形象的说法,如同打开房门就可以进入房间活动一样。 打开文件是指在文件读写之前做必要的准备工作,包括:
1)为文件流对象和指定的磁盘文件建立关联,以便使文件流流向指定的磁盘文件。
2)指定文件的工作方式,如,该文件是作为输入文件还是输出文件,是ASCII文件还是二进制文件等。
以上工作可以通过两种不同的方法实现。

1) 调用文件流的成员函数open。如
ofstream outfile; //定义ofstream类(输出文件流类)对象outfile
outfile.open(“f1.dat”,ios::out); //使文件流与f1.dat文件建立关联
第2行是调用输出文件流的成员函数open打开磁盘文件f1.dat,并指定它为输出文件, 文件流对象outfile将向磁盘文件f1.dat输出数据。ios::out是I/O模式的一种,表示以输出方式打开一个文件。或者简单地说,此时f1.dat是一个输出文件,接收从内存输出的数据。

调用成员函数open的一般形式为:
文件流对象.open(磁盘文件名, 输入输出方式);
磁盘文件名可以包括路径,如”c:\new\f1.dat”,如缺省路径,则默认为当前目录下的文件。

2) 在定义文件流对象时指定参数
在声明文件流类时定义了带参数的构造函数,其中包含了打开磁盘文件的功能。因此,可以在定义文件流对象时指定参数,调用文件流类的构造函数来实现打开文件的功能。如
ostream outfile(“f1.dat”,ios::out); 一般多用此形式,比较方便。作用与open函数相同。
输入输出方式是在ios类中定义的,它们是枚举常量,有多种选择,见表
这里写图片描述
这里写图片描述
几点说明:
1) 新版本的I/O类库中不提供ios::nocreate和ios::noreplace。

2) 每一个打开的文件都有一个文件指针,该指针的初始位置由I/O方式指定,每次读写都从文件指针的当前位置开始。每读入一个字节,指针就后移一个字节。当文 件指针移到最后,就会遇到文件结束EOF(文件结束符也占一个字节,其值为-1),此时流对象的成员函数eof的值为非0值(一般设为1),表示文件结束 了。

3) 可以用“位或”运算符“|”对输入输出方式进行组合,如表13.6中最后3行所示那样。还可以举出下面一些例子:
ios::in | ios:: noreplace //打开一个输入文件,若文件不存在则返回打开失败的信息
ios::app | ios::nocreate //打开一个输出文件,在文件尾接着写数据,若文件不存在,则返回打开失败的信息
ios::out l ios::noreplace //打开一个新文件作为输出文件,如果文件已存在则返回打开失败的信息
ios::in l ios::out I ios::binary //打开一个二进制文件,可读可写

但不能组合互相排斥的方式,如 ios::nocreate l ios::noreplace。

4) 如果打开操作失败,open函数的返回值为0(假),如果是用调用构造函数的方式打开文件的,则流对象的值为0。可以据此测试打开是否成功。如
if(outfile.open(“f1.bat”, ios::app) ==0)
cout <<”open error”;

if( !outfile.open(“f1.bat”, ios::app) )
cout <<”open error”;

文件的关闭
在对已打开的磁盘文件的读写操作完成后,应关闭该文件。关闭文件用成员函数close。如
outfile.close( ); //将输出文件流所关联的磁盘文件关闭
所谓关闭,实际上是解除该磁盘文件与文件流的关联,原来设置的工作方式也失效,这样,就不能再通过文件流对该文件进行输入或输出。此时可以将文件流与其他磁盘文件建立关联,通过文件流对新的文件进行输入或输出。如
outfile.open(“f2.dat”,ios::app|ios::nocreate);
此时文件流outfile与f2.dat建立关联,并指定了f2.dat的工作方式。

#include <iostream>#include <fstream>using namespace std;int main1(){    // 写文件  定义一个 输出文件流的对象    // 输出文件流对象,test 要打开的文件名称    // 对象创建成功,代表文件打开了    ofstream f("test");     // 可以把 f  当作 cout 用    f << "hello world" << endl;    f << "123456"  << endl;    f << "abcdefg" << endl;    f.close();    return 0;}// 读文件int main2(){    // 创建一个输入文件流对象    ifstream f("test");    // 把 f 当作 cin 用, cin 从输入缓冲区读数据,f从文件读数据    //char str[100];    //f.getline(str,100);    //cout << str << endl;    //f.getline(str,100);    //cout << str << endl;    //f.getline(str,100);    //cout << str << endl;    char ch;    while ((ch = f.get()) != EOF)    {        cout << ch;    }    f.close();    return 0;}class Student{public:    Student(){}    Student (int id, char *name)    {        this->id = id;        strcpy (this->name, name);    }    void print()    {        printf ("id = %d, name = %s\n", id, name);    }private:    int id;    char name[20];};int main(){    Student s1(10, "wang");    Student s2(20, "zhang");//  ofstream f("student", ios::binary);//  //  f.write((char *)&s1, sizeof(s1));//  f.write((char *)&s2, sizeof(s2));    ifstream f("student", ios::binary);    Student tmp;    f.read((char*)&tmp, sizeof(tmp));    tmp.print();    f.read((char*)&tmp, sizeof(tmp));    tmp.print();    return 0;}
原创粉丝点击