美文网首页
文件操作

文件操作

作者: 薛落花随泪绽放 | 来源:发表于2022-10-03 23:17 被阅读0次

    文件基本概念和文件流类

    文件的概念

    在计算机中,通常将一些内容相关的信息组织起来保存在一起并用一个名字标识,这就是文件。

    C++根据文件数据的编码方式不同分为文本文件和二进制文件。

    C++文件流类

    流是一个逻辑概念,是对所有外部设备的逻辑抽象。

    C++标准库中有3个流类可以用于文件操作。

    • ifstream:用于从文件中读取数据
    • ofstream:用于向文件中写入数据
    • fstream:既可用于从文件中读取数据,又可用于向文件中写入数据。

    打开和关闭文件

    打开文件

    在对文件进行读写操作之前,先要打开文件,打开文件有两个目的

    • 建立关联;
    • 指明文件的使用方式和文件格式。

    打开文件的方式有两种

    1. 先建立流对象,然后调用open()函数连接外部文件
    流类名 对象名;
    对象名.open(文件名,模式);
    
    1. 调用流类带参数的构造函数,在建立流对象的同时连接外部文件。
    流类名 对象名(文件名,模式);
    

    表8-1 文件打开模式标记

    模式标记 适用对象 作用
    ios::in ifstream/fstream 以读方式打开文件。如果文件不存在,则打开出错
    ios::out ofstream/fstream 以写方式打开文件。如果文件不存在,则新建该文件;如果文件已经存在,则打开时清除原来的内容
    ios::app ofstream 以追加方式打开文件,用于在文件尾部添加数据。如果文件不存在,则新建该文件
    ios::ate ofstream 打开一个已有的文件,并将文件读指针指向文件末尾。如果文件不存在,则打开出错。
    ios::trunc ofstream 删除文件现有内容。单独使用时与ios::out相同
    ios::binary ifstream/ofstream/fstream 以二进制方式打开文件。若不指定此模式,则以默认的文本模式打开文件
    ios::in | ios::out fstream/ofstream 打开已存在的文件,即可读取其内容,也可向其写入数据。文件刚打开时,原有内容保持不变。如果文件不存在,则打开出错。
    ios::in |ios::out|ios::trunc fstream 打开文件,即可读取其内容,也可向其写入数据。如果文件本来就存在,则打开时清除原来的内容,如果不存在,则新建。

    例如,要从data.txt中读取数据

    ifstream inFIle;
    inFile.open("data.txt",ios::in);
    或
    ifstream inFIle("data.txt",ios::in);
    

    关闭文件

    使用fstream中的成员函数close()关闭文件。
    程序8-1 建立流对象,然后调用open()函数连接外部文件

    #include <iostream>
    #include <fstream>
    using namespace std;
    int main()
    {
        ifstream inFile;
        inFile.open("d:\\tmp\\test.txt",ios::in);
        if(inFile)
        {
            cout<<"成功打开文件:d:\\tmp\\test.txt\n";
            inFile.close();
        }
        else
            cout<<"打开文件失败:d:\\tmp\\test.txt\n";
        ofstream outFile;
        outFile.open("test1.txt",ios::out);
        if(!outFile)
            cout<<"error1"<<endl;
        else
        {
            cout<<"成功打开文件:test1.txt\n";
            outFile.close();
        }
        outFile.open("tmp\\test2.txt",ios::out|ios::in);
        if(outFile)
        {
            cout<<"成功打开文件:tmp\\test2.txt\n";
            outFile.close();
        }
        else
            cout<<"error2"<<endl;
        fstream ioFile;
        ioFile.open("..\\test3.txt",ios::out|ios::in|ios::trunc);
        if(!ioFile)
            cout<<"error3"<<endl;
        else
        {
            cout<<"成功打开文件: ..\\test3.txt\n"<<endl;
            ioFile.close();
        }
        return 0;
    }
    

    程序8-2 调用流类带参数的构造函数打开文件

    #include <iostream>
    #include <fstream>
    using namespace std;
    int main()
    {
        ifstream inFile("d:\\tmp\\test.txt",ios::in);
        if(inFile)
        {
            cout<<"成功打开文件:d:\\tmp\\test.txt\n";
            inFile.close();
        }
        else
            cout<<"打开文件失败: d:\\tmp\\test.txt\n";
        ofstream outFile("test1.txt",ios::out);
        if(!outFile)
        {
            cout<<"error1"<<endl;
        }
        else
        {
            cout<<"成功打开文件: test1.txt\n";
            outFile.close();
        }
        fstream outFile2("tmp\\test2.txt",ios::out|ios::in);
        if(outFile)
        {
            cout<<"成功打开文件: tmp\\test2.txt\n";
            outFile.close();
        }
        else
            cout<<"error2"<<endl;
        return 0;
    }
    

    文件读写操作

    读写文本文件

    C++将文件看成顺序排列的无结构的字节流。

    程序8-3 对文本文件score.txt进行输入/输出

    #include <iostream>
    #include <fstream>
    using namespace std;
    int main()
    {
        char id[11],name[21];
        int score;
        ofstream outFile;
        outFile.open("score.txt",ios::out);
        if(!outFile)
        {
            cout<<"创建文件失败"<<endl;
            return 0;
        }
        cout<<"请输入:学号       姓名  成绩(以Ctrl+Z结束输入)\n";
        while(cin>>id>>name>>score)
            outFile<<id<<" "<<name<<" "<<score<<endl;
            outFile.close();
            return 0;
    }
    

    输入如下:


    image.png

    内容如下


    image.png

    程序8-4 读入学生成绩文件score.txt并显示内容

    #include <iostream>
    #include <fstream>
    #include <iomanip>
    using namespace std;
    int main()
    {
        char id[11],name[21];
        int score;
        ifstream inFile;
        inFile.open("score.txt",ios::in);
        if(!inFile)
        {
            cout<<"打开文件失败"<<endl;
            return 0; 
        }
        cout<<"学生学号\t 姓名\t\t     成绩\n";
        while(inFile>>id>>name>>score)
            cout<<left<<setw(10)<<id<<" "<<setw(20)<<name<<" "<<setw(3)<<right<<score<<endl;
        inFile.close();
        return 0;
    }
    
    学生学号         姓名                成绩
    20180001        zhangsan              90
    2018001002      lisi                   9
    2018001003      wangwu                85
    2018001004      zhangsanfeng         100
    2008001005      zhouwuzhengwangyishi 100
    

    程序8-5 读入文本文件,加上行号后显示内容

    #include <iostream>
    #include <fstream>
    #include <iomanip>
    using namespace std;
    int main()
    {
        char ch,filename[20];
        int count=0;
        bool newline = true;
        cout<<"请输入文件名: ";
        cin>>filename;
        ifstream inFile(filename,ios::in);
        if(!inFile)
        {
            cout<<"打开文件失败"<<endl;
            return 0;
        }
        while((ch=inFile.get())!=EOF)
        {
            if(newline)
            {
                cout<<setw(4)<<++count<<':';
                newline=false;
            }
            if(ch=='\n')
                newline=true;
            cout<<ch;
        }
        inFile.close();
        return 0;
    }
    
    请输入文件名: score.txt
       1:20180001 zhangsan 90
       2:2018001002 lisi 9
       3:2018001003 wangwu 85
       4:2018001004 zhangsanfeng 100
       5:2008001005 zhouwuzhengwangyishi 100
    

    程序8-6 对文本文件的内容排序,将结果输出到另一个文件

    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    using namespace std;
    const int MAX_NUM = 1000;
    class CStudent
    {
        public:
            char id[11];        //学号。为10位,以'\o'结尾
            char name[21];      //姓名。不超过20个字符
            int score;          //成绩 
    }stu[MAX_NUM];      //存放文件中读入的整数
    
    int MyCompare(const void * e1,const void * e2)
    {
        return (*(CStudent *)e1).score-(*(CStudent *)e2).score; 
    } 
    
    int main()
    {
        ifstream srcFile("score.txt",ios::in);
        if(!srcFile)
        {
            cout<<"opening source file error."<<endl;
            return 0;
        }
        ofstream destFile("out.txt",ios::out);
        if(!destFile)
        {
            srcFile.close();
            cout<<"opening destionation file error."<<endl;
            return 0;
        }
        int n = 0;
        cout<<"排序前:\n";
        while(srcFile>>stu[n].id>>stu[n].name>>stu[n].score)
        {
            cout<<stu[n].id<<" "<<stu[n].name<<" "<<stu[n].score<<endl;
            n++;
        }
        qsort(stu,n,sizeof(CStudent),MyCompare);
        cout<<"排序后: \n";
        for(int i=0;i<n;++i)
        {
            cout<<stu[i].id<<" "<<stu[i].name<<" "<<stu[i].score<<endl;
            destFile<<stu[i].id<<" "<<stu[i].name<<" "<<stu[i].score<<endl;
        }
        destFile.close();
        srcFile.close();
        return 0;
    }
    
    排序前:
    20180001 zhangsan 90
    2018001002 lisi 9
    2018001003 wangwu 85
    2018001004 zhangsanfeng 100
    2008001005 zhouwuzhengwangyishi 100
    排序后:
    2018001002 lisi 9
    2018001003 wangwu 85
    20180001 zhangsan 90
    2008001005 zhouwuzhengwangyishi 100
    2018001004 zhangsanfeng 100
    

    读写二进制文件

    文本文件在存储数据时是以ASCII码形式保存数据的。二进制数据文件以基本类型数据的二进制形式存放。

    C++用binary方式打开二进制文件,调用ifstream或fstream的read()成员函数从文件中读取数据,调用ofstream或fstream的write()成员函数向文件中写入数据。

    1. 用ostream::write()成员函数写文件
      ostream和fstream的write()成员函数继承自ostream类。
    ostream & write(char *buffer,int nCount);
    

    程序8-7 用二进制文件保存学生信息

    #include <iostream>
    #include <fstream>
    using namespace std;
    class CStudent
    {
        public:
            char id[11];
            char name[21];
            int score;
    };
    
    int main()
    {
        CStudent stu;
        ofstream outFile("students.dat",ios::out|ios::binary);
        if(!outFile)
        {
            cout<<"创建文件失败"<<endl;
            return 0;
        }
        cout<<"请输入:学号 姓名 成绩(以Ctrl+Z结束输入)\n";
        while(cin>>stu.id>>stu.name>>stu.score)
            outFile.write((char *)&stu,sizeof(stu));
        outFile.close();
        return 0;
    }
    

    程序8-8 向二进制文件中追加数据

    #include <iostream>
    #include <fstream>
    using namespace std;
    class CStudent
    {
        public:
            char id[11];
            char name[21];
            int score;
    };
    
    int main()
    {
        char ch;
        cout<<"确实需要向文件中追加新数据吗(Y/N)?";
        cin>>ch;
        if(ch=='Y' || ch=='y')
        {
            CStudent stu;
            ofstream outFile("students.dat",ios::app|ios::binary);
            if(!outFile)
            {
                cout<<"以追加方式打开文件失败"<<endl;
                return 0;
            }
            cout<<"请输入: 学号 姓名 成绩(以Ctrl+Z结束输入)\n";
            while(cin>>stu.id>>stu.name>>stu.score)
                outFile.write((char*)&stu,sizeof(stu));
            outFile.close();
        }
        return 0;
    }
    
    1. 用istream::read()成员函数读文件
      继承自类istream
    istream &read(char * buffer,int nCount);
    
    1. 用ostream::gcount()成员函数得到读取字节数
    int gcount();
    

    程序8-9 从二进制文件中读取数据

    #include <iostream>
    #include <fstream>
    #include <iomanip>
    using namespace std;
    
    class CStudent
    {
        public:
            char id[11];
            char name[21];
            int score;
    };
    
    int main()
    {
        CStudent stu;
        int count=0,nbyte=0;
        ifstream inFile("students.dat",ios::in|ios::binary);
        if(!inFile)
        {
            cout<<"创建文件失败"<<endl;
            return 0;
        }
        cout<<"学生学号   姓名\t\t\t成绩\n";
        while(inFile.read((char *)&stu,sizeof(stu)))
        {
            cout<<left<<setw(10)<<stu.id<<" "<<setw(20)<<stu.name<<" "<<setw(3)<<right<<stu.score<<endl;
            count++;
            nbyte += inFile.gcount();
        }
        cout<<"共有记录数: "<<count<<",字节数: "<<nbyte<<endl;
        inFile.close();
        return 0;
    }
    
    学生学号   姓名                 成绩
    2019001001 zhangsan              90
    2019001002 LiSi                 100
    2019001003 WangWu                78
    2008001005 xuexiansheng         102
    2011002004 qixiansheng          100
    共有记录数: 5,字节数: 180
    

    用成员函数put()和get()读写文件

    可以用类ifstream和类fstream的成员函数get()从文件中一次读取一个字节,也可以用类ofstream和类fstream的成员函数put()向文件中一次写入一个字节。

    函数get()有3中主要形式

    1. int get();
    2. istream& get(char &rch);
    3. istream & get(char *pch,int nCount,char delim='\n');

    函数put()语法格式

    ostream &put(char ch);
    

    程序8-10 文件复制

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main(int argc,char * argv[])
    {
        if(argc != 3)       //判断main的参数是否位3个 
        {
            cout<<"使用方法错误。正确的命令格式:mycopy SourceFile NewFile"<<endl;
            return 0;
        }
        ifstream inFile(argv[1],ios::binary|ios::in);
        if(!inFile)
        {
            cout<<"Source file open error."<<endl;
            return 0;
        }
        ofstream outFile(argv[2],ios::binary|ios::out);
        if(!outFile)
        {
            cout<<"New file open error."<<endl;
            inFile.close();
            return 0;
        }
        
        char c;
        while(inFile.get(c))
            outFile.put(c);
        outFile.close();
        inFile.close();
        return 0;
    }
    

    随机访问文件

    如果一个文件只能进行顺序存取操作,称为顺序文件。典型的是键盘、显示器和保存在磁带上的文件。

    如果一个文件可以在文件的任意位置进行存取操作,称为随机文件。磁盘文件就是随机文件。

    在访问文件的过程中,若严格按照数据保存的次序从头到尾访问文件,则称为顺序访问。

    若不必按照数据的存储次序访问文件,而是要根据需要在文件的不同位置进行访问,则称为随机访问。

    在C++中,每个流都有一个”流指针“,由系统控制,会随着对流的各种操作在字节流中移动。

    在类istream、类ifstream和类fstream中有成员函数seekg(),可以设置文件读指针的位置;

    在类ostream、类ofstream和类fstream中有成员函数seekp(),可以设置文件的写指针位置。

    类istream中与位置指针相关的函数

    1. 移动读指针函数
      istream & seekg(long pos);将读指针设置为pos。
      istream & seekg(long offset,ios::seek_dir dir); 将读指针按照seek_dir的指示移动offset个字节。

    2. 返回读指针当前位置值的函数
      long tellg(); 返回值为流中读指针的当前位置。

    类ostream中与位置指针相关的函数

    1. 移动写指针函数
      ostream & seekp(long pos);
      ostream & seekp(long offset,ios::seek_dir dir);

    2. 返回写指针当前位置的函数
      long tellp();

    程序8-11 修改程序8-7,

    #include <iostream>
    #include <fstream>
    #include <iomanip>
    using namespace std;
    class CStudent
    {
        public:
            char id[11];
            char name[21];
            int score;
    };
    
    int main()
    {
        CStudent stu;
        int count = 0,nbyte=0;
        ifstream inFile("students.dat",ios::in|ios::binary);
        if(!inFile)
        {
            cout<<"创建文件失败"<<endl;
            return 0;
        }
        else
        {
            cout<<"打开文件时位置指针: "<<inFile.tellg()<<endl;
            cout<<"     每个记录大小: "<<sizeof(CStudent)<<endl;
        }
        cout<<"学生学号   姓名\t\t\t成绩\t流指针";
        while(inFile.read((char *)&stu,sizeof(CStudent)))
        {
            cout<<left<<setw(10)<<stu.id<<" "<<setw(20)<<stu.name<<" "<<setw(3)<<right<<stu.score<<"\t"<<inFile.tellg()<<endl;
            count++;
            nbyte += inFile.gcount();
        }
        cout<<"读取文件结束时位置指针: "<<inFile.tellg()<<endl;
        cout<<"共有记录数: "<<count<<",字节数: "<<nbyte<<endl;
        inFile.clear();
        inFile.seekg(0);
        cout<<"位置指针: "<<inFile.tellg()<<endl;
        inFile.read((char *)&stu,sizeof(stu));
        cout<<left<<setw(10)<<stu.id<<" "<<setw(20)<<stu.name<<" "<<setw(3)<<right<<stu.score<<endl;
        inFile.seekg(0,ios::end);
        cout<<"位置指针: "<<inFile.tellg()<<endl;
        inFile.close();
        return 0;
    }
    
    打开文件时位置指针: 0
                    每个记录大小: 36
    学生学号   姓名                 成绩    流指针2019001001 zhangsan              90       36
    2019001002 LiSi                 100     72
    2019001003 WangWu                78     108
    2008001005 xuexiansheng         102     144
    2011002004 qixiansheng          100     180
    读取文件结束时位置指针: -1
    共有记录数: 5,字节数: 180
    位置指针: 0
    2019001001 zhangsan              90
    位置指针: 180
    

    程序8-12 读取文件,查找最高分和最低分的学生,并显示信息。

    #include <iostream>
    #include <fstream>
    #include <iomanip>
    using namespace std;
    class CStudent
    {
        public:
            char id[11];
            char name[21];
            int score;
    };
    
    int main()
    {
        CStudent stu;
        int count=0,maxScore,minScore,maxNo,minNo;
        maxScore = INT_MIN;
        minScore = INT_MAX;
        maxNo = minNo = 0;
        ifstream inFile("students.dat",ios::in|ios::binary);
        if(!inFile)
        {
            cout<<"创建文件失败"<<endl;
            return 0;
        }
        while(inFile.read((char *)&stu,sizeof(CStudent)))
        {
            if(stu.score > maxScore)
            {
                maxScore = stu.score;
                maxNo = count;
            }
            else if(stu.score < minScore)
            {
                minScore = stu.score;
                minNo = count;
            }
            count++;
        }
        inFile.clear();
        inFile.seekg(sizeof(CStudent)*maxNo,ios::beg);
        inFile.read((char *)&stu,sizeof(CStudent));
        cout<<"最高分记录: "<<maxNo<<":"<<stu.id<<","<<stu.name<<","<<stu.score<<endl;
        inFile.seekg(sizeof(CStudent)*minNo,ios::beg);
        inFile.read((char *)&stu,sizeof(CStudent));
        cout<<"最低分记录: "<<minNo<<":"<<stu.id<<","<<stu.name<<","<<stu.score<<endl;
        inFile.close();
        return 0;
    }
    
    最高分记录: 3:2008001005,xuexiansheng,102
    最低分记录: 2:2019001003,WangWu,78
    

    相关文章

      网友评论

          本文标题:文件操作

          本文链接:https://www.haomeiwen.com/subject/nxfeartx.html