VC++ 之 文件操作

文件的基本概念

本节中文件指的是磁盘文件。

C++根据文件(file)内容的数据格式,可分为两类:

  • 文本文件:由字符序列组成,在文本文件中存取的最小信息单位为字符(character),也称ASCII码文件。
  • 二进制文件:存取的最小信息单位为字节(Byte)。


C++把每个文件都看成一个有序的字节流,每一个文件或者以文件结束符(end of file marker)结束,或者在特定的字节号处结束,如下图所示。



当打开一个文件时,该文件就和某个流关联起来了。对文件进行读写实际上受到一个文件定位指针(file position pointer)的控制。

输入流的指针也称为读指针,每一次提取操作将从读指针当前所指位置开始,每次提取操作自动将读指针向文件尾移动。输出流指针也称写指针,每一次插入操作将从写指针当前位置开始,每次插入操作自动将写指针向文件尾移动。

文件的打开与关闭

文件使用的5步骤:
①说明一个文件流对象,这又被称为内部文件:
    ifstream ifile;//只输入用
   ofstream ofile;//只输出用
    fstream iofile;//既输入又输出用

②使用文件流对象的成员函数打开一个磁盘文件。这样在文件流对象和磁盘文件名之间建立联系。文件流中说明了三个打开文件的成员函数。
    void ifstream::open(const char*,int=ios::in,int=filebuf::openprot);
    voidofstream::open(const char*,int=ios::out,int=filebuf::openprot);
    void fstream::open(const char*,int,int=filebuf::openprot);
第一个参数为要打开的磁盘文件名。第二个参数为打开方式,有输入(in),输出(out)等,打开方式在ios基类中定义为枚举类型。第三个参数为指定打开文件的保护方式,一般取默认。所以第二步可如下进行:
    iofile.open(“myfile.txt”,ios::in|ios::out);

上面三个文件流类都重载了一个带默认参数的构造函数,功能与open函数一样:
    ifstream::ifstream(const char*,int=ios::in,int=filebuf::openprot);
    ofstream::ofstream(const char*,int=ios::out,int=filebuf::openprot);
    fstream::fstream(const char*,int,int=filebuf::operprot);
所以①和②两步可合成: fstream iofile(”myfile.txt”,ios::in|ios::out);

③打开文件也应该判断是否成功,若成功,文件流对象值为非零值,不成功为0(NULL),文件流对象值物理上就是指它的地址。因此打开一个文件完整的程序为:
fstream iofile(”myfile.txt”,ios::in|ios::out);
if(!iofile)
{ //“!”为重载的运算符
       cout<<”不能打开文件:”<<”myfile,txt”<<endl;
       return -1;
} //失败退回操作系统

④使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写,这在下一节中讨论。

⑤关闭文件。三个文件流类各有一个关闭文件的成员函数 :
    void ifstream::close();
    void ofstream::close();
    void fstream::close();
使用很方便,如:
    iofile.close();

关闭文件时,系统把该文件相关联的文件缓冲区中的数据写到文件中,保证文件的完整,收回与该文件相关的内存空间,可供再分配,把磁盘文件名与文件流对象之间的关联断开,可防止误操作修改了磁盘文件。如又要对文件操作必须重新打开。

关闭文件并没有取消文件流对象,该文件流对象又可与其他磁盘文件建立联系。文件流对象在程序结束时,或它的生命期结束时,由析构函数撤消。它同时释放内部分配的预留缓冲区。

文本文件的读写

文本文件的顺序读写:顺序读写可用C++的提取运算符(>>)和插入运算符(<<)进行。

例1:文件复制

#include<iostream>
#include<fstream>
#include<cstdlib>
using namespace std;

int main(){
    char ch;
    ifstream sfile("d:\\Ex9_6\\Ex9_6.cpp");
    ofstream dfile("e:\\Ex9_6.cpp");  //只能创建文件,不能建立子目录,如路径不存在则失败
    if(!sfile){
        cout<<"不能打开源文件:"<<"d:\\Ex9_6\\Ex9_6.cpp"<<endl;
        return -1;
    }
    if(!dfile){
        cout<<"不能打开目标文件:"<<"e:\\Ex9_6.cpp"<<endl;
        return -1;
    }
    sfile.unsetf(ios::skipws);      //关键!把跳过空格控制位置0,即不跳过空格,否则空格全部未拷贝
    while(sfile>>ch)dfile<<ch;
    sfile.close();                  //如没有这两个关闭函数,析构函数也可关闭
    dfile.close();
    return 0;
}

例2:按行复制文本文件

#include<iostream>
#include<fstream>
#include<cstdlib>
using namespace std;

int main(){
    char filename[256],buf[100];
    fstream sfile,dfile;
    cout<<"输入源文件路径名:"<<endl;
    cin>>filename;//对路径各方面而言空格是无关紧要的,否则要用getline()等成员函数
    sfile.open(filename,ios::in);//打开一个已存在的文件
    while(!sfile){
        cout<<"源文件找不到,请重新输入路径名:"<<endl;
        sfile.clear(0);//清状态字
        cin>>filename;
        sfile.open(filename,ios::in);
    }
    cout<<"输入目标文件路径名:"<<endl;
    cin>>filename; //只能创建文件,不能建立子目录,如路径不存在则失败
    dfile.open(filename,ios::out);
    if(!dfile){
        cout<<"目标文件创建失败"<<endl;
        return -1;
    }
    while(sfile.getline(buf,100)){//按行拷贝  A行
        if(sfile.gcount()<100) dfile<<buf<<'\n';//因回车符未送到  B行
        else dfile<<buf;//本行大于99个字符,还未读到回车换行符,所以不加'\n'
    } 
    sfile.close();
    dfile.close();
    return 0;
}

例3:文本式数据文件的创建与读取数据

#include<fstream>
#include<iostream>
#include<iomanip>
#include<string>
using namespace std;
class inventory{
    string Description;
    string No;
    int Quantity;
    double Cost;
    double Retail;
public:
    inventory(string="#",string="0",int=0,double=0,double=0);
    friend ostream&operator<<(ostream&dist,inventory&iv);//重载插入运算符
    friend istream&operator>>(istream&sour,inventory&iv);//重载提取运算符
};     //流类作为形式参数必须是引用
inventory::inventory(string des,string no,int quan,double cost,double ret){
    Description=des;
    No=no;
    Quantity=quan;
    Cost=cost;
    Retail=ret;
}
ostream &operator<<(ostream&dist,inventory&iv){
    dist<<left<<setw(20)<<iv.Description<<setw(10)<<iv.No;
    dist<<right<<setw(10)<<iv.Quantity<<setw(10)<<iv.Cost<<setw(10)<<iv.Retail<<endl;
    return dist;
}//写入文件是自动把数转为数字串后写入
istream&operator>>(istream&sour,inventory&iv){
    sour>>iv.Description>>iv.No>>iv.Quantity>>iv.Cost>>iv.Retail;
    return sour;
}//从文件读出是自动把数字串转为数读出,函数体内>>功能不变
int main(){
    inventory car1("夏利2000","805637928",156,80000,105000),car2;
    inventory motor1("金城125","93612575",302,10000,13000),motor2;
    ofstream distfile("d:\\Ex9_9.data");
    distfile<<car1<<motor1;//注意ofstream是ostream的派生类
    distfile.close();
    cout<<car1;
    cout<<motor1;
    cout<<car2;
    cout<<motor2;
    ifstream sourfile("d:\\Ex9_9.data");//这样分两次打开,可避免读文件时,误改了源文件
    sourfile>>car2>>motor2;
    sourfile.close();
    cout<<car2;
    cout<<motor2;
    return 0;
}

资源获取是由构造函数实现,而资源释放是由析构函数完成。所以与内存动态分配一样,由文件重构对象放在构造函数中,把对象存入文件则放在析构函数中。参见后面章节。

二进制文件的读写

 1、对二进制文件进行读写的成员函数
    istream&istream::read(char *,int);
    //从二进制流提取
    istream&istream::read(unsigned char*,int);
    istream&istream::read(signed char *,int);
    //第一个参数指定存放有效输入的变量地址,第二个参数指定提取的字节数,
    //函数从输入流提供指定数量的字节送到指定地址开始的单元

    ostream&ostream::write(const char *,int);
    //向二进制流插入
    ostream&ostream::write(const unsigned char *,int);
    ostream&ostream::write(const signed char *,int);
    //函数从该地址开始将指定数量的字节插入输入输出流

 2、文件结束判断:读函数并不能知道文件是否结束,可用状态函数int ios::eof()来判断文件是否结束。必须指出系统是根据当前操作的实际情况设置状态位,如需根据状态位来判断下一步的操作,必须在一次操作后立即去调取状态位,以判断本次操作是否有效。

3、例4:创建二进制数据文件,以及数据文件的读取。

#include<fstream>
#include<iostream>
#include<iomanip>
#include<string>
using namespace std;

class inventory{
    string Description;
    string No;
    int Quantity;
    double Cost;
    double Retail;
public:
    inventory(string="#",string="0",int =0,double =0,double =0);
    friend ostream &operator<<(ostream&,inventory&);
    void Bdatatofile(ofstream&dist);     //文件流类作为形式参数必须是引用
    void Bdatafromfile(ifstream&sour);
};
inventory::inventory(string des,string no,int quan,double cost,double ret){
    Description=des;
    No=no;
    Quantity=quan;
    Cost=cost;
    Retail=ret;
}
ostream &operator<<(ostream&dist,inventory&iv){
    dist<<left<<setw(20)<<iv.Description<<setw(10)<<iv.No;
    dist<<right<<setw(10)<<iv.Quantity<<setw(10)<<iv.Cost<<setw(10)<<iv.Retail<<endl;
    return dist;
}
void inventory::Bdatatofile(ofstream&dist){
    dist.write(Description.c_str(),20); //由string类的c_str()函数转为char*
    dist.write(No.c_str(),10);
    dist.write((char*)&Quantity,sizeof(int));
    dist.write((char*)&Cost,sizeof(double));
    dist.write((char*)&Retail,sizeof(double));
}
void inventory::Bdatafromfile(ifstream&sour){
    char k[20];
    sour.read(k,20);
    Description=k;
    sour.read(k,10);
    No=k;
    sour.read((char*)&Quantity,sizeof(int));
    sour.read((char*)&Cost,sizeof(double));
    sour.read((char*)&Retail,sizeof(double));
}//由此可见读和写是完全对称的过程,次序决不能错
int main(){
    inventory car1("夏利2000","805637928",156,80000,105000),car2;
    inventory motor1("金城125","93612575",302,10000,13000),motor2;
    ofstream ddatafile("d:\\Ex9_10.data",ios::out|ios::binary);
    car1.Bdatatofile(ddatafile);
    motor1.Bdatatofile(ddatafile);
    cout<<"对象car1:"<<endl;
    cout<<car1;
    cout<<"对象motor1:"<<endl;
    cout<<motor1;
    cout<<"对象car2:"<<endl;
    cout<<car2;
    cout<<"对象motor2:"<<endl;
    cout<<motor2;
    ddatafile.close();
    ifstream sdatafile("d:\\Ex9_10.data",ios::in|ios::binary);//重新打开文件,从头读取数据
    car2.Bdatafromfile(sdatafile);                         //从文件读取数据拷贝到对象car2
    if(sdatafile.eof()==0) cout<<"读文件成功"<<endl; 
    cout<<"对象car2:"<<endl;
    cout<<car2;
    motor2.Bdatafromfile(sdatafile);                 //继续从文件读取数据拷贝到对象motor2
    if(sdatafile.eof()==0) cout<<"读文件成功"<<endl;
    cout<<"对象motor2:"<<endl;
    cout<<motor2;
    sdatafile.close();
    return 0;
}

这两项操作设计为成员函数,给出与例3不同的读写方式。

4、二进制文件优点:可以控制字节长度,读写数据时不会出现二义性,可靠性高。同时不知格式是无法读取的,保密性好。文件结束后,系统不会再读(见eofbit的说明),但程序不会自动停下来,所以要判断文件中是否已没有数据。如写完数据后没有关闭文件,直接开始读,则必须把文件定位指针移到文件头。如关闭文件后重新打开,文件定位指针就在文件头。

转载于:https://www.cnblogs.com/delphi2014/p/4075495.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: VC 6.0是微软公司开发的一款集成开发环境,MFC(Microsoft Foundation Classes)是其一部分,用于开发Windows平台上的C++应用程序。在VC 6.0中,MFC提供了丰富的文件操作功能,以便开发者可以方便地进行文件的读写和处理。 MFC中的文件操作主要通过CFile类来实现。要进行文件操作,首先需要创建一个CFile对象,并指定文件名和打开模式。打开模式可以是读取(CFile::modeRead)、写入(CFile::modeWrite)、读写(CFile::modeReadWrite)等。然后,可以通过CFile对象调用相应的方法来实现文件的读写操作。 常用的文件操作方法包括Read、ReadString、ReadHuge等。其中,Read方法用于读取指定数量的字节到缓冲区中,ReadString方法用于读取一行字符串,ReadHuge方法用于读取大型文件。在读取文件前,需要使用CFile的Open方法打开文件,读取完成后,需要调用Close方法关闭文件文件操作方法包括Write、WriteString、WriteHuge等。其中,Write方法用于将指定数量的字节从缓冲区写入文件中,WriteString方法用于将字符串写入文件,WriteHuge方法用于写入大型文件。在写入文件前,也需要使用CFile的Open方法打开文件,写入完成后,同样需要调用Close方法关闭文件。 此外,MFC还提供了其他一些文件操作的辅助功能,如文件的创建与删除、文件的属性设置、文件指针的定位等。 总之,VC 6.0中的MFC文件操作功能强大且灵活,可以满足各种文件操作的需求。开发者可以根据具体的应用场景,选择适合的文件操作方法,并结合其他MFC的功能,实现更加复杂的文件处理功能。 ### 回答2: VC 6.0是微软的一款集成开发环境,MFC(Microsoft Foundation Classes)是一套用于开发Windows应用程序的C++类库。在VC 6.0中,我们可以使用MFC进行文件操作。 MFC提供了一系列的类来进行文件的创建、打开、读取、写入和关闭等操作。首先,我们可以使用CFile类来创建或打开一个文件,并进行读写操作。我们可以使用Open函数来打开一个已经存在的文件或者使用Create函数来创建一个新的文件。然后,可以使用Read和Write函数进行数据的读取和写入。最后,使用Close函数关闭文件。通过这些函数,我们可以灵活地操作文件。 另外,MFC还提供了CStdioFile类,它是对CFile类的一个高级封装。使用CStdioFile类,我们可以更方便地进行文本文件的读写操作。例如,可以使用ReadString函数逐行读取文本文件的内容,使用WriteString函数将字符串写入文本文件。 此外,MFC还提供了CFileDialog类,用于显示文件选择对话框,方便用户选择文件。通过这个类,我们可以让用户选择要打开或保存的文件,并获取用户选择的文件路径。 总结起来,VC 6.0的MFC提供了丰富的文件操作类和函数,可以方便地进行文件的读写,包括二进制文件文本文件。开发者可以根据自己的需要使用相应的类和函数来操作文件,以完成各种文件处理任务。 ### 回答3: VC 6.0的MFC(Microsoft Foundation Class)库提供了一些用于文件操作的类和函数,方便开发人员在Windows平台上进行文件的读写和管理。下面是一些常用的MFC文件操作相关的功能和类。 1. CFile类:CFile类是MFC提供的用于文件操作的基本类,它封装了文件的打开、读写、关闭等功能。通过CFile类的派生类CStdioFile可以实现文本文件的读写操作。通过CFile类的派生类CMemFile可以在内存中创建文件。 2. CString类:CString类是MFC中用于处理字符串的类,可以将字符串写入文件或从文件中读取字符串。通过CFile类的WriteString()和ReadString()函数可以方便地进行字符串的写入和读取。 3. CArchive类:CArchive类使开发人员能够方便地对对象进行序列化和反序列化操作。通过CArchive类的派生类CFile和CMemFile可以将对象保存到文件中或从文件中读取对象。 4. 文件打开对话框:MFC提供了CFileDialog类,可以通过它打开一个文件选择对话框,选择需要进行操作文件路径和文件名。 5. 文件属性操作:通过CFile类的相关函数可以获取文件的属性信息,如文件的大小、创建时间、修改时间等。 6. 文件夹和目录操作:MFC通过CFileFind类提供了对文件夹和目录的操作,可以遍历文件夹中的文件或子文件夹。 除了上述基本的文件操作类和函数外,MFC还提供了一系列的扩展类和函数,用于处理文件的权限、文件夹的创建和删除等操作。开发人员可以根据具体的需求选择合适的类和函数进行文件操作。但需要注意的是,VC 6.0已经较为古老,一些新的文件操作方式和技术,如C++文件流和Boost库等,可能在VC 6.0中并不适用。因此建议尽量使用更新的版本进行文件操作

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值