1
一、文本流和二进制流二、流文件三、文件的打开函数 fopen和关闭函数 fclose
四、格式读写 fprintf和 fscanf函数五、出错测试或清除函 (feof,ferror,clearerr)
2
一、文本流和二进制流内存中的信息会由于程序运行的结束而消失。程序运行的结果需要另外稳定的介质加以永久保存,这种可以长期保留数据的存储设备称为磁盘文件。下面几种是有影响的存储方式:
1,ANSI C 运行库缓冲流的输出输出操作
2,C 运行库低级输出输出操作
3,iotream类提供的 I/O操作
4,DOS 或 WINDOWS API 端口操作
5,Microsoft Foundation 类库的文件操作
3
在 C/C++中流可分为两类:
1) 文本流 (text stream); 1) 二进制流 (binary stream)
文本流中的数据以字符形式出现,文本以行作为结束。
图 数据的流入流出是一个相对概念流 入
cout<<b
输出输入
cin>>a
流 入磁盘内存缓冲区内存数据区键盘 stdin
stdout显示器 stderr
打印机 stdprn
4
二、流文件流文件是 C运行库函数中由 FILE结构有效处理的硬件设备的逻辑描述。在这个称为标准文件 I/O系统中,定义了三个文本流,stdin,stdout和 stderr。一般对如下前 3个标准设备,系统构筑了流文件的索引方式,其相应的非缓冲区的文件代号一并罗列如下:
硬件设备 预定义的流文件或流对象 设备代号或句柄键 盘(标准输入) stdin cin 0
显示器(标准输出) stdout cout 1
显示器(标准错误) stderr cerr 2
串行口(标准辅助) stdaux 3
打印机(标准打印) stdprn clog 4
5
描述流文件的 FILE数据结构随编译器版本的不同而相异,下面的描述摘自微软 VC 6.0 头文件 stdio.h,该结构的具体声明如下:
struct _iobuf
{ char *_ptr; //1索引数据流内容的位置指针
int _cnt; //2当前的定位标志数
char *_base; //3缓冲区基准位置
int _flag; //4文件操作模式标记
int _file; //5文件的代号
int _charbuf; //6字符缓冲信息
int _bufsiz; //7缓冲区大小
char *_tmpfname; //8临时文件名
};
typedef struct _iobuf FILE;
6
对于该结构软件供应商并未逐一指明其中每一数据成员的详细含义,标准输入输出函数的用户不要冒然直接去操作其中的成员,而通过相应的函数间接进行。
三个预定义的流文件在 vc 6.0的 stdio.h中通过通过外部说明语句和宏:
extern FILE _iob[ ];
#define stdin (&_iob[0])
#define stdout (&_iob[1])
#define stderr (&_iob[2])
就已经在内存中构建,因此不对这三个标准的 I/O设备进行建立和清除工作。但其它的流文件需要程序员调用相关的函数,进行规则的内存分配和释放工作。
7
三、文件的打开函数 fopen和关闭函数 fclose
1,文件的打开函数 fopen
文件的打开函数 fopen是为要操作的磁盘文件对应的数据结构分配内存的函数,这是一个构建 FILE的数据结构变量的初始化函数,系统通过调用类似 malloc的堆内存分配函数完成了 FILE型结构变量的内存分配。下面是 fopen函数一个简约的函数原型:
FILE * fopen (const char *filename,const char *mode);
函数返回一个指向堆空间的 FILE *型的流文件指针。不如确切地说该函数在堆空间诞生了一个 FILE型结构变量。
8
两个 const char *型的入口参数对上面的结构成员执行了部分初始化赋值。第一个参数 filename是定位磁盘文件路径的文件名,该文件名通常是双引号括起来的只读字符串。
在使用含路径的文件名时,注意,\”的使用,对于硬盘中的文件 d:\mydocu_1\ex.cpp 应写成
,d:\\mydocu_1\\ex1.cpp”
或进行如下的初始赋值,
const char *filename="d:\\mydocu_1\\ex1.cpp";
第二个以只读字符串的形式出现的参数 mode,界定文件访问操作的模式。(其有效的取值组合和含义见下一页)
9
mode 含义
"r" 以 read only 方式打开一个文本文件,如果输入文件不存在或未找到 fopen失败
"w" 以 write only方式打开一个文本文件,如果输出文件已存在,内容将全覆盖
"a" 以写和 append方式在文本文件末尾追加,如果它不存在则先建立该文件
"r+" 以读或写的方式打开一个必须已经存在的文本文件
"w+" 以读或写的方式打开一个空文件,如果给定的文件名存在原来的内容将被冲洗
"a+" 以读 /写和追加方式打开文件,如果该文件不存在则先建立它
10
"rb" 以只读方式打开一个 binary输入文件,如果文件不存在或未找到 fopen失败
"wb" 以只写方式打开一个二进制输出文件,如果文件已存在,内容将全覆盖
"ab" 以 append方式在 binary文件末尾追加,如果它不存在则先建立该文件
"rb+" 以读或写的方式打开一个必须已经存在的二进制文件
"wb+" 以读或写的方式打开一个空 binary文件,如果文件名存在原来的内容将被销毁
"ab+" 以读和追加方式打开二进制文件,如果该文件不存在则先建立它
11
指定文件的缺省操作类型取决于一个全局变量
_fmode,vc6.0 里在头文件 stdlib.h中声明为
[extern int _fmode;],系统设置的默认值是文本方式即,
_fmode=O_TEXT=0x4000
如果从文本方式切换为二进制模式,可以在程序中令:
_fmode= O_BINARY;
如果在打开文件发生错误,则 fopen都返回 NULL即 0,
其潜在的原因有:
a,以读模式打开一个并不存在的文件
b,打开一个无权操作的文件(如该文件已标明只读或隐藏属性试图写追加打开)
c,以追加方式对文件操作但磁盘空间不足
12
2.文件的关闭函数 fclose
函数 fclose专用于释放由函数 fopen申请的堆空间,及时完成缓冲区数据的到位。 fclose的函数原型为:
int fclose (FILE * fp);
fclose的函数原型为,int fclose (FILE * fp);
其中入口形参匹配函数 fopen返回的指针值,函数 fclose
调用成功返回数值 0,否则返回 EOF即 -1。
该函数不操作预定义的流文件 stdin,stdout和 stderr,
它们是指向全局结构变量的指针。这样函数调用:
fclose (fp);
就关闭了先前由 fopen函数打开的文件指针所对应的堆空间。
13
四、格式读写 fprintf和 fscanf函数
1,fprintf输出函数
fprintf输出函数的一般形式为:
int fprintf (FILE* pTarget,const char* format,argument_list);
int fprintf (流文件的目的地,格式控制串,参量列表 );
fprintf函数格式控制串与 printf中的相同。将 fprintf 的第一个形参 pTarget取为实参 stdout,其调用格式相当于
printf函数。即
fprintf (stdout,格式控制串,参量列表 );
相当于,printf (格式控制串,参量列表 );
14
在使用 fprintf将内存数据写到磁盘文件之前,先要指明磁盘文件的目的所在,因此通过 fopen函数的写模式获得目标地址。
如:
FILE *fpWrite= fopen (writeFile,"w");
如此之后就可以调用的 fprintf 函数,
如,
fprintf (fpWrite,format,v_list);
fprintf (流文件目的地,格式控制串,变量列表 );
15
2,fscanf输入函数
fscanf函数的一般形式为:
int fscanf (FILE* pSource,const char* format,address_list);
int fscanf (流文件的来源处,格式控制串,变量的地址列表);
将 fscanf的第一个形参 pSource实参化为 stdin,其调用格式相当于 scanf函数。即:
fscanf ( stdin,格式控制串,变量地址 1,变量地址 2,..,变量地址 n);
相当于:
scanf (格式控制串,变量地址 1,变量地址 2,..,变量地址 n);
16
在调用 fscanf函数将磁盘源文件中的数据送到变量所占住的内存之前,先应指明待读的磁盘文件,因此借助 fopen
函数的读模式得到数据源流的地址如:
FILE *fpRead= fopen (readFile,"r");
如此之后就可以调用输入函数 fscanf。
格式为:
fscanf (fpRead,format,address_list);
17
[例 ] 格式转换处理一个结构变量,
#include<stdio.h>
typedef struct SData
{ int nLineset; float fAdjust; int nPoint;
float fXa; float fYa; float fZa;
} CData;
void OutputData (const char *filename,const CData &d )
{ FILE *fp= fopen(filename,"w");
fprintf (fp,"%d,%f,%d\n",d.nLineset,d.fAdjust,d.nPoint);//1
fprintf (fp,"%f,%f,%f\n",d.fXa,d.fYa,d.fZa);//2
fclose (fp);
}
18
void InputData (const char *filename,CData &d )
{ FILE *fp = fopen (filename,"r");
fscanf (fp,"%d,%f,%d",
&d.nLineset,&d,fAdjust,&d.nPoint);
fscanf (fp,"%f,%f,%f",&d.fXa,&d.fYa,&d.fZa);
//2
fclose (fp);
}
19
void main (void)
{ CData s= {1,2,3,4,5,6};
OutputData ("c:\\sdata.out",s);
CData d;
InputData ("c:\\sdata.out",d);
OutputData ("c:\\cdata.out",d);
}
在文件 c:\cdata.out中输出结果为:
1,2.000000,3
4.000000,5.000000,6.000000
在文件 c:\sdata.out中输出结果为:
1,2.000000,3
4.000000,5.000000,6.000000
20
五、出错测试或清除函 (feof,ferror,clearerr)
1,feof函数测试文件结束标志
feof函数的原型为:
int feof (FILE *stream);
该函数的调用格式常为:
while (!feof (stream)) 读写循环体 ;
2,ferror函数测试流中的错误
ferror函数的原型为:
int ferror (FILE *stream);
3,clearerr函数清除错误标志为 0
clearerr函数原型为,
[void clearerr (FILE *stream);]
21