1
六、字符和字符串读写函数七、无格式转换的读写函数 fread和 fwrite
八、文件的定位九、一个简单的读写存盘程序步骤
2
六、字符和字符串读写函数
1,读取单个字符的 fgetc函数
fgetc函数的原型为,int fgetc (FILE * pSrcFile);
FILE*型的入口形参指明读取操作的来源,实参匹配
fopen打开的磁盘文件或 stdin。
该函数从磁盘文件的当前位置读取一个字符,定位源磁盘文件的位置指针向后移动一个字节。如果该指针到达文件末尾,fgetc函数返回 EOF。
注意例程 getc与函数 fgetc作用相同但可以作为函数和宏出现。 getchar()例程与 getc(stdin)一致,亦可以作为函数和宏出现 。
3
[例 ]fgetc.cpp
# include <stdio.h>
void main(void)
{ FILE* fpGet =fopen ("fgetc.cpp","r");
if (fpGet==NULL)
{ printf ("fopen failed\n"); return; } int i=0;
char buffer[512];
while (feof (fpGet)==0 && i<512)
buffer [i++]= fgetc (fpGet);
buffer[i]='\0';
printf ("%s\n",buffer);
//fclose (fpGet);
}
//程序运行的结果显示 fgetc.cpp在屏幕上
4
2,存写单个字符的 fputc函数
fputc函数的原型为,int fputc (int ch,FILE * pDstFile);
fputc函数的第一个形参 ch正是要存写到第二个形参
pDstFile关联的磁盘文件中去的字符,该函数返回第一个入口形参的实参值。
pDstFile匹配一个 fopen返回的流文件指针或 stdout,调用失败返回 EOF。
5
[例 ] fputc.cpp
# include <stdio.h>
void main (void)
{ FILE* fpGet = fopen ("fputc.cpp","r");
if ( fpGet == NULL)
{ printf ("fopen failed\n"); return; }
FILE* fpPut = fopen ("fputc.xpp","w");
if ( fpPut == NULL)
{ printf ("fopen failed\n"); return; }
while (!feof ( fpGet )) //while (feof (fpGet)==0)
fputc (fgetc (fpGet),fpPut);
fclose ( fpGet );
fclose ( fpPut );
}
6
程序运行之后即将上面的 fputc.cpp源程序转存到
fputc.xpp中。
上面单个输入输出函数其返回类型是 int型的数值,虽然处理的是仅一个字节长的字符。
因此接受这些函数的结果的变量最好定义成 int型变量即,
int ch1= fgetc ( pSrcFile );
函数一般地会自动进行截断整型高位数的处理而只存写低位。
而能不失包容性地应付占两个字节的重要结尾信息
EOF(-1)。
7
3,按行读文本串 fgets函数函数 fgets的原型为:
char * fgets(char *pDstBuffer,int num,FILE * pSrcFile);
FILE *型的入口形参 pSrcFile定位数据的来源,匹配实参 stdin或 fopen函数读模式返回的流文件的指针,从中读取
num-1个字符到 char*的入口形参 pDstBuffer标明的字符缓冲区,pDstBuffer也就是该函数的返回地址。
如果在读取 num-1个字符之前遇到换行符 \n则读入结束;然后添补一个 \0字符,以表示字符串的规则结束。
暗地里定位源磁盘文件的位置指针向后移动字符缓冲区实际拥有的字节数,pDstBuffer 匹配一个足够大的字符数组,
8
[例 ] fgets.cpp
# include <stdio.h>
void main (void)
{ FILE* fp=fopen ( "fgets.cpp","r" );
if ( fp==NULL )
{ printf ("fopen failed\n"); return; }
char sBuffer[128];
for ( int k=0;k<9;k++ )
if ( fgets ( sBuffer,128,fp )! = NULL)
printf ( "%s",sBuffer ); fclose ( fp );
}
//程序运行的结果显示 fgets.cpp在屏幕上。
9
4,按行写文本串 fputs函数函数 fputs的原型为:
int fputs (const char *pSrcBuffer,FILE * pDstFile);
文本文件的操作一般按行进行,一行一行地读一行一行地写,fgets函数执行按行读的操作,函数 fputs则按行写。
fputs函数将第一个形参定位的只读字符串送到送到第二个形参指明的目的文件中的当前位置。
如果调用成功函数返回正数,在出现错误时返回 EOF。
10
[例 ] fputs.cpp
# include <stdio.h>
void main(void)
{ FILE* fpRead = fopen ("fputs.cpp","r");
if ( fpRead == NULL )
{ printf ( "fopen r failed\n" );
return;
}
FILE* fpWrite = fopen ( "fputsw.cpp","w") ;
if ( fpWrite == NULL )
{ printf ( "fopen w failed\n" );
return;
}
11
char s [81];
while ( !feof ( fpRead ))
//while ( feof ( fpRead ) = =0)
if ( fgets ( s,81,fpRead )! = NULL )
{ fputs (s,fpWrite );
printf ( "%s",s );
}
fclose ( fpWrite );
}
//程序运行显示 fputs.cpp在屏幕上同时拷贝了一个备份在磁盘文件 fputsw.cpp中
12
七、无格式转换的读写函数 fread和 fwrite
函数直接读写磁盘文件的二进制数据,读写过程数据的信息未发生转换。因而空间效率和时间效率都比较高。
1,函数 fread的原型为:
size_t fread (void * pDst,size_t size,
size_t items,FILE * pSrc);
第一个参数 pDst定位读取数据的存放位置,匹配任意集合类型的起始地址。
第二个参数 size指出数据的类型大小 ;
size = sizeof ( type )。
13
第三个参数 items指出数据的最大项数,常对应数组的维数,单一变量或对象常取 1。
第四个参数是 FILE * 型的入口形参 pSrc,指明读入数据的来源。
fread返回实际读取的项数,函数从输入文件中最多读取 items项数,每一项含有 size字节,并将它们放入 pDst起始的内存中。
如果错误发生则所读的结果是游移的。 与 pSrc关联的位置指针向后移动实际读取的字节数。
14
2,fwrite存写函数函数 fwrite的原型为:
size_t fwrite(const void * pSrc,size_t size,
size_t items,FILE * pDst );
一般地 fread总是读取原先由 frwite存写的二进制数据 ;
第一个参数入口形参 pSrc定位所写数据的源位置,匹配任意集合类型的起始地址。
第四个参数入口形参 pDst指向待存写的目的地即与
pDst相关联的磁盘文件。
其余两个参数同 fread函数。
15
函数 fwrite 返回实际所存写的数据项的个数,如出现错误返回值可少于 items。
fwrite函数从 pSrc定位地址起尽量转送 items个数据项到输出流文件中,位置指针递增实际所写的字节数。
上面两个函数都存在 void*的指针用于宽泛地定位内存的地址,但由于其含糊性必伴随具有 size_t 类型的具体参数严格划定数据的边界,这是 void*型形参函数的共性。
一般地 fread总是读取原先由 frwite 存写的二进制数据。
16
[例 ]直接随机方式处理结构变量和数组
#include<stdio.h>
typedef struct SData
{ int nLineset; float fAdjust; int nPoint;
float fXa; float fYa; float fZa;
} CData;
void WriteData ( CData pSrc[ ],int n,FILE *fpDst )
{ switch (n)
{ case 1:
fwrite ( pSrc,sizeof (CData),1,fpDst); break;
default:
fwrite ( pSrc,sizeof (CData),n,fpDst ); }
}
inline void ReadData (CData* pDst,int n,FILE *fpSrc )
{ fread ( pDst,sizeof ( CData ),n,fpSrc ); }
17
void PrintData ( const CData &d )
{ printf (“%4d,%4.1f,%4d,%4.1f,%4.1f,%4.1f\n”,
d.nLineset,d.fAdjust,d.nPoint,d.fXa,d.fYa,d.fZa);
}
void main (void)
{ CData s = {0,1,2,3,4,5};
CData d[ ]= {1,2,3,4,5,6,2,3,4,5,6,7,3,4,5,6,7,8};
FILE* fpWrite = fopen ( "c:\\cdata.dat","w");
if ( fpWrite == NULL)
{ printf ( "fopen w failed\n" ); return;}
WriteData ( &s,1,fpWrite );
WriteData ( d,3,fpWrite );
fclose ( fpWrite );
FILE* fpRead = fopen ( "c:\\cdata.dat"," r" );
18
if ( fpRead = = NULL )
{ printf ( "fopen r failed\n" ); return;}
CData b [4];
ReadData ( b,3,fpRead );
ReadData ( b+3,1,fpRead );
for ( int k=0; k<4; k++ )
PrintData ( b[k] );
}
c:\cdata.dat文件的长度为 4*6*4=96个字节,屏幕显示结果为,0,1.0,2,3.0,4.0,5.0
1,2.0,3,4.0,5.0,6.0
2,3.0,4,5.0,6.0,7.0
3,4.0,5,6.0,7.0,8.0
19
fread和 fwrite函数因其 void*入口参数而可以匹配任意类型的变量地址,而称为随机读写函数。
但实际上数据的类型属性转移到 size_t参数上去了,这个 size_t参数 n=sizeof (type)协同函数在定位好的内存空间中读写数据。
因此数据类型属性的匹配依然是环环相扣不可轻易错位的。即此类型的函数操作此类型的数据。随机读写应根据数据类型的匹配关系为:
void WriteData ( CData*pSrc,int n,FILE *
fpDst) { fwrite (pSrc,sizeof (CData),n,fpDst);}
void ReadData (CData* pDst,int n,FILE *
fpSrc) {fread (pDst,sizeof(CData),n,fpSrc);}
20
八、文件的定位
1,ftell函数告知当前位置
FILE结构的声明中有一个 char *型指针成员 _ptr即索引数据流内容的位置指针,该指针潜在地指向当前文件的位置。
当用户首次打开流文件进行读写操作时,操作系统把该位置指针设置在文件的开头。
但特别地以追加方式 a打开文件时,位置指针定位于文件的结尾处。每次读写一个字符时,位置指针向前移动一个字符。
如果从文件中读写一行文本,位置指针一般移到该行末尾或下一行开始处。
21
ftell函数告知当前位置函数 ftell的原型为:
long ftell (FILE * stream);
函数返回的 long型值为指定文件中的当前位置相对于流文件起始位置的字节偏移量,stream一般匹配 fopen函数打开的文件。
[例 ]ftell.cpp
#include<stdio.h>
void main (void)
{ FILE * stream= fopen ( "ftell.cpp","rb") ;
double a[20];
fread ( a,sizeof (double),20,stream);
printf ( "%d\n",ftell (stream)); } //输出 160
22
2,fseek函数探寻文件的位置函数 fseek用于在一个打开的文件中重新定位文件的位置指针,如果成功返回结果 0,否则返回非 0值,在不能探寻的设备上返回的结果是不定的。其函数原型为:
int fseek (FILE *stream,long offset,int origin);
// fseek(文件指针,偏移量,起始位置 );
起始位置参量 origin的取值范围必须是如下的宏名或随后具体的常数,含义为:
#define SEEK_CUR 1 //文件当前位置
#define SEEK_END 2 //文件结束位置
#define SEEK_SET 0 //文件开始位置
23
fseek函数在 stream形参所对应的文件中运作,将其中的位置指针变动到新的位置,新的位置由 offset算定。
偏移量参量 offset指出距离 origin起始位置的字节偏移数,正的 long型实参表示以起始位置为基准前移 offset个字节作为新的位置,负的实参则后移。
在流上的下一回合操作以新的位置为基准,一般可安全地用于二进制文件。
fseek函数操作文本文件的结果漂移于回车换行次数的不确定性。
24
3,rewind函数反绕到文件开头位置
rewind函数原型为:
void rewind ( FILE *stream );
函数 rewind重新定位与 stream关联的位置指针到文件的开头。
函数调用 [ rewind (stream ); ]近似于:
(void) fseek ( stream,0L,SEEK_SET );
但不象 fseek,函数 rewind清除文件结束符和 stream的出错标记。
25
九、一个简单的读写存盘程序步骤读写存盘操作是程序设计中的重要工作,程序的读写操作主要包含如下步骤和特点:
1,构筑待存盘操作的数据结构,不同的数据结构对应不同的函数 ;
2,明晰数据的来源和走向,屏幕操作利用格式转换函数以进行字符处理 ;
3,格式化输出一般用于显示数据,格式化磁盘输入常严格呼应格式化输出函数 ;
4,非格式化函数直接在内存和磁盘之间输送数据无需信息转换,
26