c++文件处理

来源:互联网 发布:数据结构与算法笔试 编辑:程序博客网 时间:2024/05/22 12:57

1.文件分类

按照文件的存取方式分

顺序文件:结构简单,文件中的数据按顺序存放。在顺序文件中,只知道第一条记录的存放位置。当要查找某条记录时,只能从文件头开始,按顺序查找,直到找到为止。

随机文件:又称直接存取文件,简称随机文件或直接文件。随机文件的每条记录都 有一个记录号,即在写入数据时,只要指定记录号,就可以把数据写到指定的位置。在读取文件时,只要给出记录号,就可以直接读取。

按照数据编码方式分

文本文件:是按ASCII码进行编码的文件,可以用字处理软件建立和修改(必须以纯文本文件保存)

二进制文件:顾名思义,以按二进制编码的文件,不能用普通的字处理软件编辑,占空间较小。

1.1 文件操作的过程

用户程序在处理文件时,只需遵从如下的步骤即可:

1)打开文件。

2)读取文件。

3)处理数据。

4)写回(根据需要)

5)关闭文件。

1.2 处理文件流的类

在C中,处理文件必须通过一个结构体FILE。这个结构体的主要内容就是文件名、文件起始位置、大小、当前读写位置信息等信息。在处理文件的过程中,用户程序必须要通过这个结构体进行。如果打开文件 用fopen()函数、读数据的fprintf()函数、关闭文件的fclose()函数等。

例如:

#include<iostream>using namespace std;int main(){    FILE *pFile=fopen("a.txt","r+");//以读写方式打开文件     if(NULL == pFile)//文件是否存在     {      cout<<"打开文件失败"<<endl;      system("pause");      return 0;    }    char str[256];    while(EOF!=fscanf(pFile,"%s",str))//读取文件内容,以空格或者回车分隔     {      cout<<str<<endl;//输出一行     }    fprintf(pFile,"END");//在文件尾部写入"END"     fclose(pFile);//关闭文件     system("pause");    return 0;}

写完后文档内容如下:

事实上,通过FILE结构对文件进行操作并不是很理想。主要是因为这么做并不符合面向对象的思想。因此,c++提供了一系列专门用于处理文件的文件流类。这些类包括专门用于从文件中输入数据的ifstream类,专门用于向文件输出数据的ofstream类,以及即可输入也可以输出的fstream类。


需要注意的是,文件编码有ASCII码和UNICODE编码之分,相应的处理文件的类也有这样的分别。上述的ifstream、ofstream和fstream类都是用于处理ASCII编码的文件。如果要处理UNICODE编码的文件,则应当使用对应的wifstream、wofstream和wfstream。以下只针对ASCII码格式的文件流类进行说明。

文件流例1:

#include<iostream>#include<fstream>//#include<cstdlib> //#include<cstdio> //#include<stdio.h>using namespace std;int main(){ fstream file; file.open("a.txt");//没有指定打开方式,默认是读写。  if ( file.fail() ) {      cout<<"打开文件失败"<<endl;      system("pause");      return 0; } char str[256]; while(file>>str) {  cout<<str<<endl; } file << "fstream";//没有写进去,为什么????  file.close(); system("pause"); return 0;}

2.文件的打开与关闭

首先是创建流,然后把流和文件关联,才能进行输入、输出操作,完成后要关闭文件。

三个输入输出流类:ofstream,ifstream,fstream.

2.1打开文件

打开文件就是用函数open()把某一个流与文件建立联系。open()函数是上述三个流类的成员函数,定义在fstream.h中,它的原型为

void open(const unsigned char * ,int mode,int access=filefuf::openprot);

其中,第一个参数为字符串类型,其用来传递文件名。第二个参数是int型,其值决定文件撕开的方式,用数据流基类ios_base的数据成员指定。一般来讲每种流都有固定的打开模式。如输入文件流ifstream就是ios_base::in,输出文件流ofstream就是ios_base::out。即便是编程时给错了打开方式也不会出问题。

例如:构造输入文件流对象时,用的打开模式却是ios_base::out。这种情况下并不会影响文件的读入。同时也不要企图向文件中写入数据,因为输入文件流ifstream没有输出函数。第三个参数的值决定文件的访问方式及文件的类别,默认方式是filebuf::openprot。在DOS/Windows环境中,access的值分别对应DOS/Windows的文件属性代码如下:

0 普通文件1 只读文件2 隐含文件3 系统文件8 备份文件

例2:在当前文件夹下创建一个文本文件,并向其中写入一个字条串。

#include<iostream>#include<fstream>using namespace std;int main(){ ofstream sfile("sssfile.txt"); sfile<<"Hello world"<<endl; system("pause");}

例3:创建一个文件,然后打开该文件,如果文件不存在,则返回错误信息;否则提示文件已打开的信息。

#include<iostream>#include<fstream>using namespace std;int main(){    ofstream ofile("file1.txt");    ifstream ifile;    ofile<<"welcome to China";    ifile.open("file1.txt");    if(ifile.fail())       cout<<"文件不存在,打开失败!"<<endl;    else        cout<<"文件已打开,可以进行读写操作"<<endl;    ifile.close();    system("pause");    return 0; }

2.2关闭文件

文件使用后,必须将其关闭,否则可能导致数据丢失。关闭文件就是将文件与流的联系断开,用函数close()完成,它也是流类中的成员函数,没有参数,没有返回值,其参数原型为:

对象名.close()

例:下面程序用open()函数打开一个文件,并判断其是否打开,但不管其是否打开成功,在程序结束时均需要关闭文件。

 #include <fstream>  #include <iostream>  using namespace std; int main()  {   ifstream in;  in.open("file1.txt");  if (in.fail())       cout<<"文件不存在,打开失败"<<endl;  else       cout<<"文件已打开,可以进行读写操作"<<endl;  in.close();  cout<<"文件已关闭"<<endl;  system("pause");   return 0; }

fail()函数是流类中的成员函数,可用该函数测试文件是否存在。若存在,返回0,否则返回非0。

在程序语句中,可将定义流与打开文件用一条语句完成,如:

 #include <fstream.h>  #include <iostream>  using namespace std; int main() {  // fstream f("testf.txt",ios::in|ios::out);//如果只是fstream f("testf.txt");不会创建文件。要如此行代码或者fstream f("testf.txt",ios::out)        ofstream f("testf.txt",ios::out);//ofstream默认就是out.所以ofstream f("testf.txt")与本行代码一个效果        f<<"helloworld"<<endl;       system("pause"); }
一般情况下,ifstream和ofstream流类的析构函数就可以自动关闭已打开的文件,但若需要使用同一个流对象打开的文件,则需要首先用close()函数关闭当前文件。

3.文件的顺序读写

3.1读写文本文件

对文本文件进行读写时,先要以某种方式打开文件,然后使用运算符“<<”和">>"进行操作,同时必须将运算符"<<"和">>"前的cin和cout与文件关联的流代替。

下面程序先向文件test.txt中写入三行数据,再将该文件打开,并将写入的数据依次输出到屏幕。

#include<fstream.h>#include<iostream>using namespace std;int main(){  ofstream fout("test.txt");      if (!fout)//创建失败  {    cout<<"不能打开输出文件。"<<endl;    return 1;  }  fout<<"HelloWorld"<<endl;//注意这HelloWorld中间没有空格   fout<<10<<endl;  fout<<hex<<10<<endl;  fout.close();  ifstream fin("test.txt");  if (!fin)  {    cout<<"不能打开输入文件"<<endl;    return 1;  }  char c[20];  int i;  char ch;  fin>>c;  fin>>i;  fin>>ch;  cout<<c<<endl;  cout<<i<<endl;  cout<<ch<<endl;  fin.close();  system("pause");  return 0;} 


例:下面程序实现对一个文本文件的多种操作,包括求文件长度、统计单词长度等功能。

#include<iostream>#include<fstream>using namespace std;void open(char str[])//打开文件函数,把文件内容传给str; { int i=0; ifstream f; f.open("test.txt",ios::in);//ifstream默认就是ios::in,此处可以省略  if (!f) {  cout<<"not open"<<endl;  return ; } while (f) {   f.get(str[i]);//一个一个取字符,包括空格。可参见myblog:cin\cin.get()\cin.getline()\getline()\gets()\getchar()用法集锦   i++; }  str[i]='\0';//在读到的字符串最末加上'\0'。  f.close(); cout<<str<<endl;} int len(char str[])//求字符串长度函数 {  int temp=0;  for(int i=0;'\0'!=str[i];i++)     temp++;  return temp;}int index(char a[],char b[])//找子串函数,返回子串首次出现的位置。 {    int i,j,temp;    for(i=0;i<len(a)-len(b);i++)    {      temp=i;      j=0;      while(j<=len(b)&&a[temp]==b[j])//对i位置及后面的字符,逐个字符判断是否字串      {        temp++;        j++;      }       if(j==len(b))//找到         return i;    }    return -1;}int count(char str[])//统计单词个数 {  int i,c=0;  for(i=0;i<len(str);i++)     if(' '==str[i])         c++;     return c+1;//以单词之间空格个数+1表示单词个数。比如3个单词间有2个空格。 }void output(char a[])//输出当前文本 {  for(int i=0;i<len(a);i++)      cout<<a[i];  cout<<endl;}void output(char a[],int)//输出第一个单词 {  for(int i=0;i<len(a);i++)      if(' '==a[i])          break;      else      cout<<a[i];  cout<<endl;}int main(){ char m[100]; char n[]="ok"; open(m); cout<<"字符串长度:"<<len(m)-1<<endl; cout<<"目标单词首次出现的位置:"<<index(m,n)<<endl; cout<<"单词数:"<<count(m)<<endl; cout<<"当前文本是:"<<endl; output(m);//输出当前文本 cout<<"第一个单词是:";  output(m,1);//输出第一个单词  system("pause"); return 0;}


3.2读写二进制文件

二进制文件是一种不能用普通的字处理软件进行编辑、占空间较小的文件。二进制文件与文本文件的区别有以下几点:

1)文本文件是字符流,二进制文件是字节流。

2)文本文件在输入时,将回车和换行两个字符转换为字符"\n",输出是将字符"\n"转换为回车和换行两个字符,二进制文件不做这种转换。

3)文本文件遇到文件结束符时,用get()函数返回一个文件结束标志EOF,该标志的值为-1。二进制文件用成员函数eof()判断文件是否结束。其中,eof()函数的原型为:int eof();

4)当文件达到末尾时,返回一个非零值;未达到末尾时返回零值。当从键盘输入字符时,结束符为<Ctrl>+z组合键。

任何文件,都能以文本方式或者二进制方式打开。对以二进制方式打开的文件,有两种方式进行读写操作:一种是使用函数get()和put(),另一种是使用函数read()和write()。

3.2.1使用get()和put()读写二进制文件

get()函数是输入流类istream中定义的成员函数,作用是从与流对象连接的文件中读出数据,get()实现的功能是从流中每读出一个字节或一个字符放入引用&ch中,返回一个流输入对象值。在c++中,get()函数原型为:

istream &get(unsigned char &ch);

put()函数是输出流类ostream中定义的成员函数,作用是向与流对象连接的文件中写入数据,put()实现的功能是每次将一个字节或一个字符写入流中,同时返回一个流输入对象值。在c++中,put()函数的原型为:

istream &put(char ch);

get()函数和put()函数都只能对单个字符或者单个字节进行操作,如果需要实现多字符的操作,可通过循环语句来实现。

例如,下面程序用函数get()和put()读写二进制文件。该程序定义一个命令,在DOS下调用该命令可以实现将文件1的内容拷贝到文件2中,相当于DOS命令中的copy命令。

#include<fstream>#include<iostream>using namespace std;int main(int arg,char *argv[]){    char ch;    if(arg!=3)    {      cout<<"命令行输入错误!"<<endl;      return 1;    }    ifstream fin(argv[1]);//定义输入流对象,打开第二个参数中的文件    if(!fin)    {      cout<<"不能打开源文件"<<endl;      return 1;    }     ofstream fout(argv[2]);    if(!fout)    {      cout<<"不能打开目标文件"<<endl;      return 1;    }    while(fin)//循环写入    {      fin.get(ch);//从源文件中读出字符       fout.put(ch);//写入到目标文件     }     fin.close();    fout.close();    system("pause");    return 0;}
在DOS界面下输入:XX.exe test1.txt test2.txt就能找test1.txt中的内容复制到test2.txt中。前提是test1.txt文件存在,test2.txt如果不存在会自动创建。

3.2.2使用函数read()和write()读写二进制文件

除了上述内容中讲解的使用函数get()和put()读写二进制文件外,c++还支持使用函数read()和write()读写二进制文件。

read()函数是输入流类istream中定义的成员函数,其最常用的原型为:

istream &read(unsigned char *buf,int num);

该函数的作用是从相应的流中读出num个字节或字符的数据,把它们放入指针所指向的缓冲区中。第一个参数buf是一个指向读入数据存放空间的指针,它是读入数据的起始地址;第二个参数num是一个整数值,该值说明要读入数据的字节或字符数。该函数的调用格式为:

read(缓冲区首地址,读入的字节数);

需要注意的是,“缓冲区首地址”的数据类型为“ unsigned char* ”,当输入其他类型数据时,必须进行类型转换。

write()函数是输出流类ostream中定义的成员函数,其最常用的原型为:

 ostream &write(const unsigned char *buf,int num);

该函数的作用是从buf所指向的缓冲区把num个字节的数据写到相应的流中。其参数的含义、调用及注意事项与read()相同。

例如:下面程序用函数read()和write()读写二进制文件,实现向文件test.txt写入一个双精度数据类型的数值和一个字符串,并将该文件中的内容读取出显示到屏幕中。

#include<fstream>#include<string.h>#include<iostream>using namespace std;int main(){  ofstream outf("test.txt");  if (!outf)  {    cout<<"不能打开输出文件"<<endl;    return 1;  }  double n=123.4;  char str[]="向文件写入双精度数和字符串";//13个中文,每个中文占2字节。相当于26个字节,也相当于26个char。   outf.write((char *)&n,sizeof(double));  outf.write(str,strlen(str));  outf.close();  ifstream inf("test.txt");  if (!inf)  {    cout<<"不能打开输入文件!"<<endl;    return 1;  }  inf.read((char *)&n,sizeof(double));//读取文件中的内容  inf.read(str,26);  cout<<n<<" "<<str<<endl;  inf.close();  system("pause");  return 0; }

文件里显示的内容如下:


3.3 文件的随机读写

随机读写是通过使用输入或输出流中与随机移动文件指针相关的成员函数,通过随机移动文件指针而达到随机访问的。移动文件指针的成员函数主要有 seekg()和seekp(),它们的常用原型为:

istream &seekg(streamoff offset,seek_dir origin);

osream &seekp(streamoff  offset,seek_dir origin);

其中,参数origin表示文件指针的起始位置,offset表示相对于这个起始位置的位移量。seek_dir是系统定义的枚举名,origin是枚举变量。origin的取值有以下三种情况。

ios::beg 从文件头开始,把文件指针移动由offset指定的距离。

ios::cur 从文件当前位置开始,把文件指针移动offset指定的距离。

ios::end 从文件尾开始,把文件指针移动由offset指定的距离。

显然,当origin的值为ios::beg时,offset为正;当origin的值为ios::end时,offset的值为负;当origin的值为ios::cur时,offset的值可正可负。offset的值 为正数时从前向后移动文件指针,为负数时从后向前移动文件指针。位移量offset的类型是streamoff,该类型为一个long型数据,它在头文件iostream.h中定义如下:

typedef streamoff long;

此外,移动文件指针的成员函数seekg()和seekp()使用范围和功能为:

函数seekg()用于输入文件,将文件的读指针从origin说明的位置移动offset个字节。

函数seekp()用于输出文件,将文件的写指针从origin说明的位置移动offset个字节。

进行文件随机读写时,可以用下列函数确定文件当前指针的位置:

streampos tellg();

streampos tellp();

其中,streampos是在头文件iostream.h中定义的类型;是long型的;函数tellg()用于输入文件;函数tellp()用于输出文件。

#include<fstream.h>#include<stdlib.h>#include<iostream>using namespace std;int main(int argc,char *argv[]){  char ch;  if(3!=argc)  {    cout<<"命令行输入错误"<<endl;    return 1;  }      ifstream fin(argv[1]);  if (!fin)  {    cout<<"不能打开输入文件"<<endl;    return 1;  }   fin.seekg(atoi(argv[2]),ios::beg);//从源文件的头开始读取参数3指定的距离   while(!fin.eof())  {    fin.get(ch);    cout<<ch;  }  fin.close();  system("pause");  return 0;}
用dos打开程序后,输入xxx.ext test.txt 5。表示从text.txt的第3个位置开始读取数据。

综合例子:读写不同操作系统中文件,首先创建文件,写入数据后读取并显示在屏幕上。

#include<iostream>#include<fstream>#ifdef WIN32 #define TEST_FILE "test.txt"#else#define TEST_FILE "/tmp/test.txt" //如果win32路径为"c:\\tmp\\test.txt" #endifusing namespace std;int test(){  {   fstream sfs("test.txt",ios_base::out);//文件是写入方式,会覆盖原来的内容    char buf[]="1234567890";   sfs.write(buf,sizeof(buf));   sfs.close();  }  {    int len;    char* buf;    fstream sfs("test.txt");    sfs.seekg(0,ios::end);//定位到文件末尾     len =sfs.tellg();//返回地址,相当于获取文件的长度     sfs.seekg(0,ios::beg);//获取完之后,将指针提到文件前面     buf = new char[len];    sfs.read(buf,len);//读取文件内容到buf     cout<<buf<<endl;    delete []buf;    sfs.close();  }}int main(){ test(); system("pause"); return 0;}

文件中显示

例:模拟一个邮件发送端。在DOS命令行下输入XXX.exe mail.txt。相应的信息会写入mail.txt这个文本中。

#include<iostream> #include<cstdlib>#include<fstream>#include<string>using namespace std;int main(int argc,char *argv[]){    assert(argc>1);    ofstream file;    file.open(argv[1]);    if (!file)    {      cout<<"打开文件失败"<<endl;      system("pause");      return 0;    }    int count=0;    file.write((char*)&count,sizeof(int));    string str;    cout<<"——请输入收件人邮箱,以-1结束——"<<endl;    while(cin>>str && str!="-1")    {      file<<str<<' ';      count++;    }    long pos = file.tellp();//获取当前的输出位置     file.seekp(ios_base::beg);//重定位到文件开头     file.write((char*)&count,sizeof(int));//写入收信人信息数目     cout<<"——请输入发件人邮箱——"<<endl;    file.seekp(pos);//重定位     if (cin>>str)    {      file<<str<<' ';    }    cout<<"——请输入主题——"<<endl;    if(cin>>str)    {     file<<str<<' ';    }    cout<<"——邮件内容以-1结束——"<<endl;    while(cin>>str && str!="-1")    {     file<<str<<' ';    }    file.close();    system("pause");    return 0;}

例:模拟一个邮件读取端。读取邮件显示的屏幕。

#include<cstdlib>#include<iostream>#include<fstream>#include<string>using namespace std;int main(int argc,char* argv[]){  assert( argc > 1);  ifstream file;  file.open(argv[1]);  if (!file)  {   cout<<"打开文件失败"<<endl;   system("pause");   return 0;   }  string str;  int count = 0;  file.read((char*)&count,sizeof(int));//读取收件人信箱个数  cout<<"——收件人信箱——"<<endl;    for( int i=0;i<count;i++)  {    file>>str;    cout<<str<<endl;  }  cout<<"——发件人信箱——"<<endl;  file>>str;  cout<<str<<endl;  cout<<"——主题——"<<endl;  file>>str;  cout<<str<<endl;  cout<<"——内容——"<<endl;  while (file>>str)  {    cout<<str<<endl;  }   file.close();  system("pause");  return 0;}


补充参考:

C++二进制文件读写

cin\cin.get()\cin.getline()\getline()\gets()\getchar()用法集锦

按行拆分文件blog



原创粉丝点击