C C++ 文件输入与输出

原文地址为: C C++ 文件输入与输出

 C语言:

一 打开关闭文件

1 fopen函数 用于打开文件

FILE *fopen(char *filename, *type);

fopen("c:\\ccdos\\clib", "rb");  如果成功的打开一个文件, fopen()函数返回文件指针,否则返回空指针(NULL)。由此可判断文件打开是否成功。

"r" 打开文字文件只读        

"w" 创建文字文件只写          

"a" 增补,如果文件不存在则创建一个

"r+" 打开一个文字文件读/写

"w+" 创建一个文字文件读/写

"a+" 打开或创建一个文件增补

"b" 二进制文件(可以和上面每一项合用)

"t" 文这文件(默认项)

2. fclose()函数
fclose()函数用来关闭一个由fopen()函数打开的文件,其调用格式为:

int fclose(FILE *stream);该函数返回一个整型数。当文件关闭成功时,返回0,否则返回一个非零值。可以根据函数的返回值判断文件是否关闭成功。

二 有关文件操作的函数

本节所涉及到的文件读写函数均是指顺序读写,即读写了一条信息后,指针自动加1.

下面分别介绍写操作函数和读操作函数。   

1. 文件的顺序写函数

fprintf()、fputs()和fputc()函数均为文件的顺序写操作函数,其调用格式如下:

int fprintf(FILE *stream, char *format, <variable-list>);

int fputs(char *string, FILE *steam);

int fputc(int  ch, FILE *steam); 上述三个函数的返回值均为整型量。

fprintf() 函数的返回值为实际写入文件中的字符个数(字节数)。如果写错误,则返回一个负数;

fputs()函数返回0时表明将string指针所指的字符串写入文件中的操作成功, 返回非0时,表明写操作失败。

fputc()函数返回一个向文件所写字符的值,此时写操作成功,否则返回EOF(文件结束结束其值为-1, 在stdio.h中定义)表示写操作错误。  

fprintf( ) 函数中格式化的规定与printf( ) 函数相同,所不同的只是fprintf()函数是向文件中写入。而printf()是向屏幕输出

例如:

fputs("Your score of TOEFLis", fp);/*向所建文件写入一串字符*/
fputc(':', fp);    /*向所建文件写冒号:*/
fprintf(fp, "%d\n", i); /*向所建文件写一整型数*/
fprintf(fp, "%s", s);  /*向所建文件写一字符串*/

2. 文件的顺序读操作函数

  函数fscanf()、fgets()和fgetc()均为文件的顺序读操作函数,其调用格式如下:

int fscanf(FILE *stream, char *format, <address-list>);      

char fgets(char *string, int n, FILE *steam);

int fgetc(FILE *steam);      

fscanf()函数的用法与scanf()函数相似,只是它是从文件中读到信息。 fscanf()函数的返回值为EOF(即-1), 表明读错误,否则读数据成功。读到空白字符自动返回。

fgets()函数从文件中读取至多n-1个字符(n用来指定字符数), 并把它们放入string指向的字符串中,在读入之后自动向字符串未尾加一个空字符,读成功返回string指针,失败返回一个空指针。

fgetc()函数返回文件当前位置的一个字符,读错误时返回EOF。

3. 文件的随机读写

有时用户想直接读取文件中间某处的信息, 若用文件的顺序读写必须从文件 头开始直到要求的文件位置再读, 这显然不方便。Turbo C2.0提供了一组文件的 随机读写函数, 即可以将文件位置指针定位在所要求读写的地方直接读写。

文件的随机读写函数如下:

int fseek (FILE *stream, long offset, int fromwhere);

int fread(void *buf, int size, int count, FILE *stream);

int fwrite(void *buf, int size, int count, FILE *stream);

long ftell(FILE *stream);

fseek()函数的作用是将文件的位置指针设置到从fromwhere开始的第offset 字节的位置上, 其中fromwhere是下列几个宏定义之一:

文件位置指针起始计算位置fromwhere

━━━━━━━━━━━━━━━━━━━━━━━━━━━

符号常数 数值 含义

───────────────────────────

SEEK_SET 0 从文件开头

SEEK_CUR 1 从文件指针的现行位置

SEEK_END 2 从文件末尾

━━━━━━━━━━━━━━━━━━━━━━━━━━━

offset是指文件位置指针从指定开始位置(fromwhere指出的位置)跳过的字节数。它是一个长整型量, 以支持大于64K字节的文件。

fseek()函数一般用于对 二进制文件进行操作。当fseek()函数返回0时表明操作成功, 返回非0表示失败。

fread()函数是从文件中读count个字段, 每个字段长度为size个字节, 并把 它们存放到buf指针所指的缓冲器中。

fwrite()函数是把buf指针所指的缓冲器中, 长度为size个字节的count个字 段写到stream指向的文件中去。

随着读和写字节数的增大, 文件位置指示器也增大, 读多少个字节, 文件位 置指示器相应也跳过多少个字节。读写完毕函数返回所读和所写的字段个数。

ftell()函数返回文件位置指示器的当前值,这个值是指示器从文件头开始 算起的字节数, 返回的数为长整型数, 当返回-1时, 表明出现错误。

下面程序把一个浮点数组以二进制方式写入文件test_b.dat中。

例14:

#include <stdio.h>

main()

{

float f[6]={3.2, -4.34, 25.04, 0.1, 50.56, 80.5};

/*定义浮点数组并初始化*/

int i;

FILE *fp;

fp=fopen("test_b.dat", "wb"); /*创建一个二进制文件只写*/

fwrite(f, sizeof(float), 6, fp);/*将6个浮点数写入文件中*/

fclose(fp); /*关闭文件*/

}

下面例子从test_b.dat文件中读100个整型数, 并把它们放到dat数组中。 例15:

#include <stdio.h>

main()

{

FILE *fp;

intdat[100];

fp=fopen("test_b.dat", "rb");/*打开一个二进制文件只读*/

if(fread(dat, sizeof(int), 100, fp)!=100)

/*判断是否读了100个数*/

{

if(feof(fp))

printf("End of file"); /*不到100个数文件结束*/

else

printf("Read error"); /*读数错误*/

fclose(fp); /*关闭文件*/

}

注意:

当用标准文件函数对文件进行读写操作时, 首先将所读写的内容放进缓冲区, 即写函数只对输出缓冲区进行操作, 读函数只对输入缓冲区进行操作。例如向一 个文件写入内容, 所写的内容将首先放在输出缓冲区中, 直到输出缓冲区存满或使用fclose()函数关闭文件时, 缓冲区的内容才会写入文件中。若无fclose()函数, 则不会向文件中存入所写的内容或写入的文件内容不全。有一个对缓冲区 进行刷新的函数, 即fflush(), 其调用格式为:

int fflush(FILE *stream);该函数将输出缓冲区的内容实际写入文件中, 而将输入缓冲区的内容清除掉。

4. feof()和rewind()函数

这两个函数的调用格式为:

int feof(FILE *stream);

int rewind(FILE *stream);

feof()函数检测文件位置指示器是否到达了文件结尾,若是则返回一个非0值, 否则返回0。这个函数对二进制文件操作特别有用, 因为二进制文件中,文件结尾标志EOF也是一个合法的二进制数,只简单的检查读入字符的值来判断文件是否结束是不行的。如果那样的话, 可能会造成文件未结尾而被认为结尾, 所以就必须有feof()函数。

下面的这条语句是常用的判断文件是否结束的方法。

while(!feof(fp))

fgetc(fp);

rewind()函数用于把文件位置指示器移到文件的起点处, 成功时返回0,否则, 返回非0值。

C语言本身并不提供输入输出语句,输入和输出操作是由函数来实现的。在C标准函数库中提供了一些输入输出函数,例如,printf函数和scanf函数。

基于C++的文件操作

在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:

1、插入器(<<) 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。

2、析取器(>>) 从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。

在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。

一、打开文件 在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:

void open(const char* filename,int openmode,int access);

参数:

filename:  要打开的文件名 mode:    要打开文件的方式
access:   打开文件的属性 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:

ios::app:   以追加的方式打开文件 ios::ate:   文件打开后定位到文件尾,ios:app就包含有此属性
ios::binary:  以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文 ios::in:    文件以输入方式打开(文件=>程序) ios::out:   文件以输出方式打开 (程序=>文件) ios::nocreate: 不建立文件,所以文件不存在时打开失败  ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
ios::trunc:  如果文件存在,把文件长度设为0 可以用“或”把以上属性连接起来,如ios::out|ios::binary

打开文件的属性取值是:

0:普通文件,打开访问 1:只读文件 2:隐含文件 4:系统文件 可以用“或”或者“+”把以上属性连接起来 ,如3或1|2就是以只读和隐含属性打开文件。

例如:以二进制输入方式打开文件c:\config.sys

fstream file1; file1.open("c:\\config.sys",ios::binary|ios::in,0);

如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:

file1.open("c:\\config.sys");<=>file1.open("c:\\config.sys",ios::in|ios::out,0);

另外,fstream还有和open()功能一样的构造函数,对于上例,在定义的时侯就可以打开文件了:

fstream file1("c:\\config.sys");

特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件(文件=>程序),而ofstream默认以输出方式打开文件。

ifstream file2("c:\\pdos.def");//以输入方式打开文件 ofstream file3("c:\\x.123");//以输出方式打开文件

所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。

二、关闭文件 打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。

三、读写文件 读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式

1、文本文件的读写 文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:

file2<<"I Love You";//向文件写入字符串"I Love You" int i; file1>>i;//从文件输入一个整数值。

这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些

操纵符 功能 输入/输出 dec 格式化为十进制数值数据 输入和输出 endl 输出一个换行符并刷新此流 输出 ends 输出一个空字符 输出 hex 格式化为十六进制数值数据 输入和输出 oct 格式化为八进制数值数据 输入和输出
setpxecision(int p) 设置浮点数的精度位数 输出

比如要把123当作十六进制输出:file1<<<123;要把3.1415926以5位精度输出:file1<<<3.1415926。

2、二进制文件的读写 ①put() put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。

②get() get()函数比较灵活,有3种常用的重载形式:

一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。

另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。

还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:

file2.get(str1,127,'A');//从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。

③读写数据块 要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:

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

read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。

例:

unsigned char str1[]="I Love You"; int n[5]; ifstream in("xxx.xxx"); ofstream out("yyy.yyy"); out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中 in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换 in.close();out.close();

四、检测EOF 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();

例:  if(in.eof())ShowMessage("已经到达文件尾!");

五、文件定位 和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时, 相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是 seekg()和 seekp(),seekg()是设置读位置,seekp是设置写位置。它们最通用的形式如下:

istream &seekg(streamoff offset,seek_dir origin); ostream &seekp(streamoff offset,seek_dir origin);

streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:

ios::beg:  文件开头 ios::cur:  文件当前位置 ios::end:  文件结尾
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。

例:

file1.seekg(1234,ios::cur);//把文件的读指针从当前位置向后移1234个字节 file2.seekp(1234,ios::beg);//把文件的写指针从文件开头向后移1234个字节

-------------------------------------------------------------------------------------------------------------------------------------------------------------

文本文件读写:

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


int main()
{
//文本文件打开方式设为可读写
// fstream outfile("f1.dat",ios::out|ios::in);
// if (!outfile)
// {
// cout<<"open error!"<<endl;
// exit(1);
// }

// char a[10];// cout<<"输入十个数字"<<endl;
// //写入文件中
// for (int i=0;i<10;i++)
// {
// cin>>a[i];
// outfile<<a[i]<<' ';
// }
// //从文件读取
// for (int i=0;i<10;i++)
// {
// outfile>>a[i];
// cout<<a[i]<<' ';
// }
// outfile.close();


//从键盘读入一行字符,将其中的字母存在磁盘文件
// ofstream outfile("f2.dat");
// if (!outfile)
// {
// cout<<"open error"<<endl;
//   exit(1);
// }// char c[80];
// cin.getline(c,80);//最多提取80个字符,或者遇到默认终止符\n结束
// for (int i=0;c[i]!='\0';i++)
// {
// if (c[i]>=65&&c[i]<=90||c[i]>=97&&c[i]<=122)
// {
// //outfile.put(c[i]);或者
// outfile<<c[i];
// cout<<c[i];
// }
// }
// cout<<endl;
// outfile.close();

//从上面的文件读入字符,将其中的小写字母改写为大写字母在存在f3文件
ifstream infile("f2.dat");
if (!infile)
{
cout
<<"openerrr";
  exit(1);
} ofstream outfile3(
"f3.dat");
if (!outfile3)
{
cout
<<"error";
  exit(1);
}
char ch;
while (infile>>ch/*infile.get(ch)*/)
{
if (ch>=97&&ch<=122)
{
ch
=ch-32;
}
outfile3
<<ch;
cout
<<ch;
}
cout
<<endl;
infile.close();
outfile3.close();

return 0;

}

二进制文件读写:

主要用istream类的成员函数read 和write来实现 ,成员函数原型:

istream& read(char *buffer,int len);

ostream& write(const char *buffer,int len);

字符指针指向内存中一段存储空间,len是读写的字节数。

#include <fstream>
#include
<iostream>
using namespace std;
struct student
{
char name[20];
int num;
int age;
char sex;
};
int main()
{
student stu[
3]={"Li",1001,18,'f',"Fun",1002,19,'f',"Wa",1003,17,'m'};
ofstream outfile(
"student.dat",ios::binary);//和文件后缀名没关系,即使写成student.txt还是打开乱码,因为编码是自定义的,默认的字符编码解释不了的。
if (!outfile)
{
cerr
<<"open erroe";
exit(
1);
}
// for (int i=0;i<3;i++)
// {
// //outfile.write((char *)&stu[i],sizeof(stu[i]));
// outfile.write((char *)(stu+i),sizeof(stu[i]));
// }
//取代for循环,直接一句话
outfile.write((char *)stu,sizeof(stu));
outfile.close();


//读取
ifstream infile("student.dat",ios::binary);
if (!infile)
{
cerr
<<"open error";
exit(
1);
}
student stu2[
3];
infile.read((
char*)stu2,sizeof(stu2));
infile.close();

//打印
for (int i=0;i<3;i++)
{
cout
<<stu2[i].name<<endl;
cout
<<stu2[i].age<<endl;
cout
<<stu2[i].num<<endl;
cout
<<stu2[i].sex<<endl;

}
return 0;

}

注意

fstream iofile("student.dat",ios::in|ios::out|ios::binary);

if(!iofile)

{cout<<"open error";

exit(1);} //不知道为何新建一个能输入输出的二进制文件总会出错,二上面例子中新建一个输入输出的文本文件可以。

随机访问二进制数据文件

利用seekg(),seekp等成员函数移动指针,随机的访问文件中任意位置上的数据。

举例:(文件读写有两个指针,读文件指针和写指针。)

iofile.seekg(2*sizeof(stu[2]),ios::beg);把输入指针移动到第三个学生数据开头

iofile.read((char *)&stu2[0],sizeof(stu2[0]));

iofile.seekp(2*sizeof(stu[2]),ios::beg);把输出指针移动到第三个学生数据开头

iofile.write((char *)&stu2[0],sizeof(stu2[0]));


转载请注明本文地址: C C++ 文件输入与输出

猜你喜欢

转载自blog.csdn.net/dearbaba_8520/article/details/81736878