教学内容:
文件的概念
文件的位置
文件流
文件访问
在前边的课程里,我们的数据都是放在内存里,一旦程序结束,数据就会消失。为了长久的保存数据,我们可以把数据存放到文件里边。这一节课我们一起讨论一下文件的相关概念。
一、文件的概念
文件简单的说就是电脑中存放的一组数据的集合。类似于内存里一块连续的数据,与内存数据的区别在于文件一般是保存在硬盘上即使电脑断电后不会不消失,方便我们多次访问或者修改。
二、文件的位置
文件的位置一般有文件头,当前位置,文件尾这三个位置。
0 |
1 |
2 |
3 |
4 |
5 |
6 |
|
|
|
|
|
|
|
|
|
文件头 当前位置 文件尾
三、文件流
C库提供了读写数据流的函数来访问操作文件。流也是外部数据或者数据目的地的抽象表示,所以键盘,显示器上的命令行和磁盘文件都是流。因为可以使用输入输出函数读写映谢为流的任意外部设备。
这里我们主要讨论文件流,将数据写入流(文件)有两种方式。
1、一种是写入文本文件,此时数据写入为字符,这些字符组织为数据行,每一行都用换行符结束。(二进制数据,如int 或者double类型的值,必须先转换成字符才能写入文本文件)
2、另一种是写入二进制文件,写入二进制文件的数据总是写入为一系列的字节,与它在内存中的表示形式相同。
四、文件访问
在C语言中操作处理文件时,是通过文件指针来引用文件的。
文件指针是一个抽象的指针,它关联到要访问的一个特定文件上,所有的程序可以在不同的情况下处理不同的文件。文件指针指向表示流的结构。
如果要同时使用几个文件,就需要对每个文件使用不同的文件指针,但使用完一个文件后,可以将文件指针关联到另一个文件上。因此,如果要处理多个文件,但一次只处理一个,那么用一个文件指针就够了。
l 打开文件fopen
l 建立文件
l 关闭文件fclose
一、打开文件fopen
FILE *fopen( const char *filename, const char *mode );
filename是要操作的文件名。
mode |
说明 |
"w" |
打开一个文本文件,进行写入操作。如果文件不存在,则会建立一个新文件. 存在则清空内容。 |
"a" |
打开一个文本文件,进行追加操作。如果文件不存在,则会建立一个新文件. 存在则追加内容。 |
"r" |
打开一个文本文件,进行读取操作。 |
"w"
FILE* f;
f=fopen("test.txt","w");
f=fopen("test.txt","a");
f=fopen("test.txt","r");
二、关闭文件fclose
int fclose( FILE *stream );
#include <stdio.h> int main(void) { FILE* f; f=fopen("test.txt","r"); fclose(f); getchar(); getchar(); return 0; }
l 写入文本文件fputc
l 读取文本文件fgetc
FILE *fopen( const char *filename, const char *mode );
filename是要操作的文件名。
mode |
说明 |
"w" |
打开一个文本文件,进行写入操作。如果文件不存在,则会建立一个新文件. 存在则清空内容。 |
"a" |
打开一个文本文件,进行追加操作。如果文件不存在,则会建立一个新文件. 存在则追加内容。 |
"r" |
打开一个文本文件,进行读取操作。 |
"w"
FILE* f;
f=fopen("test.txt","w");//指针指向文件头
f=fopen("test.txt","a");//指针指向文件尾
f=fopen("test.txt","r"); //指针指向文件头,如果打开失败会返回NULL
关闭文件fclose
int fclose( FILE *stream ); //如果成功关闭返回0,不成功则返回EOF,EOF一般定义为-1;
一、写入文本文件fputc
int fputc( int c, FILE *stream );
功能:向文件写入一个字符,且指针下移。
二、读取文本文件fgetc
int fgetc( FILE *stream );
功能:从文件中获取一个字符,且指针下移。
#include <stdio.h> int main(void) { FILE* f; char i; f=fopen("test.txt","w");//"w","a" for (i='A';i<='Z';i++) { fputc(i,f); } fclose(f);//重要 f= fopen("test.txt","r"); for (i=1;i<=26;i++) { printf("%c",fgetc(f)); } fclose(f); getchar(); getchar(); return 0; }
l 将字符串写入文本文件fputs
l 从文本文件中读取字符串fgets
一、将字符串写入文本文件fputs
int fputs( const char *string, FILE *stream ); //int fputs(char *pstr,FILE *pfile);
string待写入的字符串地址;
stream表示文件指针
一、从文本文件中读出字符串fgets
char *fgets( char *string, int n, FILE *stream ); //char* fgets(char *pstr,int ncahrs,FILE *pfile);
string是用于存放字符串的缓冲区。
n表示要读出字符的个数。
stream表示文件指针
int puts( const char *string ); //把字串输出到控制台屏幕 相当于 printf("%s",string);
char *gets( char *buffer );; //从控制台读取字符串 相当于 scanf("%s",buffer);
#include <stdio.h> int main(void) { FILE* f; char i; char s[256]; ////写字符串 f=fopen("test.txt","w");//以写入模式打开文件 gets(s);//scanf("%s",s);//从控制台读取字符串 fputs(s,f);//向文件test.txt写入字符串s fclose(f);//关掉指针与文件的关联 //读字符串 f=fopen("test.txt","r");//以读取模式打开文件test.txt fgets(s,256,f);//从文件读取字串到s地址开始的缓存区 puts(s);//printf("%s",s); 把字串输出到控制台显示出来 或者理解为向控制台屏幕写入字符串 fclose(f);//关掉指针与文件的关联 getchar(); getchar(); return 0; }
l 格式化文件输出fprintf
l 格式化文件输入fscanf
fputc和fgetc是读写文件字符操作相关函数。 //putc,getc是控制台输入输出字符的函数
fputs和fgets是读写文件字符串操作相关函数。 //puts,gets 是控制台输入输出字符串的函数
一、格式化文件输出fprintf
int fprintf( FILE *stream, const char *format [, argument ]...);//printf 输出到控制台
其作用是格式化输出到文件中;
例:fprintf(pfile,"%d%f",n1,f1);//把n1格式化为字串存到文件,把f1格式化为字串存到文件
输出整数
输出浮点数
输出字符
输出字符串
////写字符串
f=fopen("test.txt","w");//以写入模式打开文件
fprintf(f,"%10d%10d%16f %s",111,222,f1,"xxxbbb");
printf("%d %d %f %s",111,222,f1,"xxxbbb");
fclose(f);//关掉指针与文件的关联
二、格式化文件输入fscanf
int fscanf( FILE *stream, const char *format [, argument ]... );//scanf从控制台获取输入
从一个流/文件中执行格式化输入到变量
例:fscanf(pfile,"%d%d",&n1,&n2); //从文件中读取整数到n1和n2中
//读字符串
//f=fopen("test.txt","r");//以读取模式打开文件test.txt
//fscanf(f,"%d%d%f%s",&n1,&n2,&f1,s);
//printf("%d %d %f %s",n1,n2,f1,s);
//fclose(f);//关掉指针与文件的关联
#include <stdio.h> int main(void) { FILE* f; char i; char s[256]; int n1,n2; float f1=77.888f; ////写字符串 f=fopen("test.txt","w");//以写入模式打开文件 fprintf(f,"%10d%10d%16f %s",111,222,f1,"xxxbbb"); printf("%d %d %f %s",111,222,f1,"xxxbbb"); printf(" "); fclose(f);//关掉指针与文件的关联 //读字符串 f=fopen("test.txt","r");//以读取模式打开文件test.txt fscanf(f,"%d%d%f%s",&n1,&n2,&f1,s); printf("%d %d %f %s",n1,n2,f1,s); fclose(f);//关掉指针与文件的关联 getchar(); getchar(); return 0; }
l 文件重命名rename
l 文件删除remove
文件重命名rename
int rename( const char *oldname, const char *newname );
oldname //需要重命名的文件名
newname //新的文件名
文件删除remove
int remove( const char *path );
文件全路径
c:\windows\system\test.txt 不能写为c:windowssystem est.txt
因为\才表示""
文件名不能包含:/*?"<>| 这几个字符
#include <stdio.h> int main(void) { //rename("test.txt","abc.txt"); remove("dabc.txt"); getchar(); getchar(); return 0; }
l 标准流stdin,stdout,stderr
l 流的重定向freopen
l 清空流缓冲区fflush
一、标准流stdin,stdout,stderr
标准输入流stdin:
是程序可以读取其输入的位置。缺省情况下,进程从键盘读取 stdin 。
fscanf(stdin,"%d%d%f%s",&n1,&n2,&f1,s); //相当于 scanf("%d%d%f%s",&n1,&n2,&f1,s); scanf隐含了stdin;
标准输出流stdout:
是程序写入其输出的位置。缺省情况下,进程将 stdout 写到终端屏幕上。
fprintf(stdout,"%10d%10d%16f %s",111,222,f1,"xxxbbb"); //相当于printf("%10d%10d%16f %s",111,222,f1,"xxxbbb"); printf隐含了stdout
标准错误流stderr:
是程序写入其错误消息的位置。缺省情况下,进程将 stderr 写到终端屏幕上
fprintf(stderr,"出错了 ");//区别于printf("出错了 ");
二、流的重定向freopen
区别:stdin和stdout都可以被重定向,stderr不能
如
FILE*f= freopen("test.txt","r",stdin); printf("%s",fgets(f)); //成功则返回 stdin指针
f= freopen("test.txt","r",stdin);//把stdin重定向至test输入
f= freopen("con","r",stdin); //重定向到键盘con表示控制台键盘输入设备
三、清空流缓冲区fflush
int fflush( FILE *stream ); // 返回0表示成功,非零表示出错
int main(void) { FILE* f; char i; char s[256]; f= freopen("test.txt","r",stdin);//把stdin重定向至test输入 gets(s,256); //fgets(s,256,f); //gets本身是从stdin获取输入的, //重定向后就从test.txt获取输入了相当于f=fopen("test.txt","r");fgets(s,256,f); printf("%s ",s); fclose(f); f= freopen("con","r",stdin); //重定向到键盘con表示控制台键盘输入设备 fflush(stdin); //清除stdin缓冲区 system("pause");//暂停按任意键继续 fclose(f);//这个fcolse的位置很关键 getchar(); getchar(); return 0; }
函数名:freopen
声明:FILE *freopen( const char *path, const char *mode, FILE *stream );
所在文件: stdio.h
参数说明:
path: 文件名,用于存储输入输出的自定义文件名。
mode: 文件打开的模式。和fopen中的模式(如r-只读, w-写)相同。
stream: 一个文件,通常使用标准流文件。
返回值:成功,则返回一个path所指定文件的指针;失败,返回NULL。(一般可以不使用它的返回值)
功能:实现重定向,把预定义的标准流文件定向到由path指定的文件中。标准流文件具体是指stdin、stdout和stderr。其中stdin是标准输入流,默认为键盘;stdout是标准输出流,默认为屏幕;stderr是标准错误流,一般把屏幕设为默认。
下面以在VC下调试“计算a+b”的程序举例。
C语法:
#include <stdio.h> int main() { int a,b; freopen("debug\in.txt","r",stdin); //输入重定向,输入数据将从in.txt文件中读取 freopen("debug\out.txt","w",stdout); //输出重定向,输出数据将保存在out.txt文件中 while(scanf("%d %d",&a,&b)!=EOF) printf("%d ",a+b); fclose(stdin);//关闭文件 fclose(stdout);//关闭文件 return 0; }
C++语法 #include <stdio.h> #include <iostream.h> int main() { int a,b; freopen("debug\in.txt","r",stdin); //输入重定向,输入数据将从in.txt文件中读取 freopen("debug\out.txt","w",stdout); //输出重定向,输出数据将保存在out.txt文件中 while(cin>>a>>b) cout<<a+b<<endl; // 注意使用endl fclose(stdin);//关闭文件 fclose(stdout);//关闭文件 return 0; }
freopen("debug\in.txt","r",stdin)的作用就是把标准输入流stdin重定向到debug\in.txt文件中,这样在用scanf或是用cin输入时便不会从标准输入流读取数据,而是从in.txt文件中获取输入。只要把输入数据事先粘贴到in.txt,调试时就方便多了。
类似的,freopen("debug\out.txt","w",stdout)的作用就是把stdout重定向到debug\out.txt文件中,这样输出结果需要打开out.txt文件查看。
需要说明的是:
1. 在freopen("debug\in.txt","r",stdin)中,将输入文件in.txt放在文件夹debug中,文件夹debug是在VC中建立工程文件时自动生成的调试文件夹。如果改成freopen("in.txt","r",stdin),则in.txt文件将放在所建立的工程文件夹下。in.txt文件也可以放在其他的文件夹下,所在路径写正确即可。
2. 可以不使用输出重定向,仍然在控制台查看输出。
3. 程序调试成功后,提交到oj时不要忘记把与重定向有关的语句删除。
l stderr错误流
l perror显示错误信息
l msdn
一、stderr流
一般说来,应将错误信息写入stderr,标准错误流stderr总是指向显示屏幕。
stdin和stdout都可以重定向到某个文件。但stderr流不能定向到文件。也不能重定向到其它流。
言归正传,我们来看看错误的处理。如:在读取文件时我们最好是能检测文件是否存在。
如:
char *filename="test.txt";
FILE *pfile=NULL;
pfile=fopen(filename,"r");//返回空表示打开文件失败
if (pfile==NULL)
{
//错误信息
}
二、perror
如果能知识错误类型,对我们很有作用。perror()函数可以输出将变量传给它的字符串,以及显示对应的系统定义错误信息。
perror(filename);
#include <stdio.h> int main(void) { //未重定向的代码 char num[256]; FILE *f; f=fopen("test.txt","r"); //fprintf(f,"ddddd"); if (f==NULL) //if (!f) { //fprintf(stderr,"文件打开出错或者是文件不存在 ");//stdout perror("test.txt"); } getchar(); getchar(); return 0; }
l 打开二进制文件
l 写二进制文件
l 读二进制文件
一、打开二进制文件
FILE *fopen( const char *filename, const char *mode );
filename是要操作的文件名。
mode |
说明 |
"wb" |
打开一个二进制文件,进行写入操作。如果文件不存在,则会建立一个新文件. 存在则清空内容。 |
"ab" |
打开一个二进制文件,进行追加操作。如果文件不存在,则会建立一个新文件. 存在则追加内容。 |
"rb" |
打开一个二进制文件,进行读取操作。 |
二、写二进制文件
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
//count*size 是要写入文件的字节数
buffer是缓冲区指针
stream是文件指针(或者流指针)
三、读二进制文件
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
//count*size 是要读取的字节数
buffer是缓冲区指针
stream是文件指针(或者流指针)
l 文件定位操作
l fgetpos定位
l fsetpos设定位置
l 文件结束判断函数feof
一、文件定位操作
在C语言标准库里
获取文件位置的函数有ftell和fgetpos
设置文件位置的函数有fseek和fsetpos
一般是ftell与fseek配对使用。
而fgetpos和fsetpos配对使用。
二、找出我们在文件中的位置
int fgetpos(FILE*pfile,fpos_t*position);
fpost_t here=0;//fpos_t 一般是 long类型,不同的系统可能有不同的区别 所以最好用fpost typedef
fgetpos(pfile,&here);
//f=fopen("test.txt","wb");
//fgetpos(f,&pos);
// //打印文件位置
//printf("文件位置:%d, ",pos);
//for(i=1;i<=256;i++)
//{
// fwrite(&i,sizeof(int),1,f);//4*256=1024
//}
//fgetpos(f,&pos);
//printf("文件位置:%d, ",pos);
三、在文件中设定位置
与fgetpos配对的函数是fsetpos
int fsetpos(FILE*pfile,fpos_t*position);
fpost_t here=10;//fpos_t 一般是 long类型,不同的系统可能有不同的区别 所以最好用fpost typedef
fsetpos(pfile,&here);
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <stdarg.h> #include <time.h> #include "hello.h" int main(void) { int i; FILE *f; fpos_t pos; //long pos; int temp; //f=fopen("test.txt","wb"); //fgetpos(f,&pos); // //打印文件位置 //printf("文件位置:%d, ",pos); //for(i=1;i<=256;i++) //{ // fwrite(&i,sizeof(int),1,f);//4*256=1024 //} //fgetpos(f,&pos); //printf("文件位置:%d, ",pos); f=fopen("test.txt","rb"); pos=(256-20)*sizeof(int);//4*20 // fsetpos(f,&pos); while(!feof(f)) { fread(&temp,sizeof(int),1,f); printf("%d,",temp); } getchar(); getchar(); return 0; }
四、文件结束判断函数feof
函数名: feof
功 能: 检测流上的文件结束符
用 法: int feof(FILE *stream);
feof(fp)有两个返回值: 如果遇到文件结束,函数feof(fp)的值为1,否则为0。
提示:位置是以字节来计量的.
int i;
FILE *f;
fpos_t pos; //long pos;
int temp;
//f=fopen("test.txt","wb");
//fgetpos(f,&pos);
// //打印文件位置
//printf("文件位置:%d, ",pos);
//for(i=1;i<=256;i++)
//{
// fwrite(&i,sizeof(int),1,f);//4*256=1024
//}
//fgetpos(f,&pos);
//printf("文件位置:%d, ",pos);
f=fopen("test.txt","rb");
pos=(256-20)*sizeof(int);//4*20
// fsetpos(f,&pos);
while(!feof(f))
{
fread(&temp,sizeof(int),1,f);
printf("%d,",temp);
}
l 文件定位操作
l 找出我们在文件中的位置ftell
l 在文件中设定位置fseek
一、文件定位操作
在C语言标准库里
获取文件位置的函数有ftell和fgetpos
设置文件位置的函数有fseek和fsetpos
一般是ftell与fseek配对使用。
而fgetpos和fsetpos配对使用。
二、找出我们在文件中的位置
long ftell (FILE *pfile);
long fpos=ftell(pfile); //fgetpos 通过指针返回fpost_t 位置
三、在文件中设定位置
与ftell配对的函数是fseek
int fseek(FILE*pfile,long offset,int origin);
SEEK_CUR //可正可负
指向当前位置
SEEK_END // - 负
文件结束位置
SEEK_SET // + 正
文件开始
成功,返回0,否则返回其他值。
fseek(f, 20,SEEK_CUR) ; //指针后移20字节的位置
fseek(f, -20,SEEK_END) ; //从文件结束位置前移20字节的位置
fseek(f, -20,SEEK_SET) ; //这样写执行会不成功,对于SEEK_SET 应该指定正数 向后移指针才行 fseek(f,20,SEEK_SET)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <stdarg.h> #include <time.h> #include "hello.h" int main(void) { int i; FILE *f; fpos_t pos; //long pos; int temp; //f=fopen("t.txt","wb"); //printf("%d,",ftell(f)); //fgetpos 代替 //for (i=101;i<=356;i++) //{ // fwrite(&i,sizeof(int),1,f);//1024字节 // printf("%d,",ftell(f)); //} //fseek读取数据 f=fopen("t.txt","rb"); //fseek //读取末尾的个int数据 fseek(f,0,SEEK_END);//指向文件尾 pos=ftell(f);//1024 if(fseek(f,pos/2,SEEK_SET)!=0) {//文件中间512 printf("fseek 失败 "); } fseek(f,100,SEEK_CUR); //612/4=153+101 while(!feof(f)) { fread(&temp,sizeof(int),1,f); printf("%d,",temp); } getchar(); getchar(); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <stdarg.h> #include <time.h> #include "hello.h" #include <share.h> int Findbyte(char* pbuffer,int buffersize,char*bydata,int size) { int pos=-1; int flag=1; int i,j; //逐字节比较 for (i=0;i<buffersize-size;i++) { flag=1; for (j=0;j<size;j++) { if(pbuffer[i+j]!=bydata[j]) { flag=0; break; } } // for j if (flag) { pos=i; return pos; } }// for i return pos; } //函数原型 int Findbyte(FILE *f,char*bydata);//bydata就是要搜索字节集数据地址。 //如果搜索的字节只有 5字节也可以这样写 int findbyte(FILE *f,char*bydata) { int pos; long filelong; char *pbuffer; fseek(f,0,SEEK_END); filelong=ftell(f); rewind(f);//重置文件指针//相当于 fseek(f1,0,SEEK_SET); //分配缓冲区 pbuffer=malloc(filelong+1);//多分配一字节,以保证有足够的空间 //读取文件数据到缓冲区 if (! fread(pbuffer,filelong,1,f)) { perror("read error:"); } /* for (i=0;i<filelength;i++) { printf("%d,",pbuffer[i]); }*/ //搜索特征串函数 pos= Findbyte(pbuffer,filelong,bydata,5); } int main(void) { FILE *f1,*f2; char s1[256]; char *filename="share.txt"; long filelength; char *pbuffer; char bydata[5]={0x2,0x3,0x4,0x5,0x6}; char bydata7[7]={13,14,15,16,17,18,19}; char i; int pos; printf("start: "); fflush(stdout); f1=f2=NULL; f2=fopen(filename,"wb"); for (i=0;i<122;i++) { fwrite(&i,1,1,f2);//写入供测试数据 } fclose(f2); printf("end: "); fflush(stdout);//清空,更新输出缓冲区,就是让前边的end及时的显示出来 f1=_fsopen(filename,"rb",_SH_DENYRW);//独占文件访问wb if (!f1) { perror("打开出错"); }else { fgets(s1,256,f1); printf("%s ",s1); } //获取文件长度 fseek(f1,0,SEEK_END); filelength=ftell(f1); rewind(f1);//重置文件指针//相当于 fseek(f1,0,SEEK_SET); //分配缓冲区 pbuffer=malloc(filelength+1);//多分配一字节,以保证有足够的空间 //读取文件数据到缓冲区 if (! fread(pbuffer,filelength,1,f1)) { perror("read error:"); } /* for (i=0;i<filelength;i++) { printf("%d,",pbuffer[i]); }*/ //搜索特征串函数 pos= findbyte(f1,bydata); //作业中的函数//////////// printf(" 特征码位置pos=%d ",pos); //bydata7 pos= Findbyte(pbuffer,filelength,bydata7,7); //扩展的,功能更强,参数更多的函数 printf(" 特征码位置pos=%d ",pos); fclose(f1); getchar(); getchar(); return 0; }
l _fsopen参数说明
l #include<share.h>
l _fsopen 共享模式访问文件
//安全性比fopen高
_fsopen
以共享的方式打开文件或者流
FILE *_fsopen( const char *filename, const char *mode, int shflag );
filename Name of the file to open. //需要打开的文件名
mode Type of access permitted. //可以访问的类型
shflag Type of sharing allowed. //共享访问类型
_SH_COMPAT Sets Compatibility mode for 16-bit applications. //以兼容模式打开16位程序
_SH_DENYNO Permits read and write access. //充许读和写 以此模式打开类似fopen
_SH_DENYRD Denies read access to the file. //拒绝读
_SH_DENYRW Denies read and write access to the file. //拒绝读和写
_SH_DENYWR Denies write access to the file //拒绝写
#include <share.h> int main(void) { FILE *f1,*f2; char s1[256],s2[256]; //同时打开文件读取 /*f1=fopen("share.txt","r"); f2=fopen("share.txt","r");*/ f1=f2=NULL; f1=_fsopen("share.txt","r",_SH_DENYRW);//独占文件访问wb // f2=_fsopen("share.txt","r",_SH_DENYRW); if (!f1) { perror("打开出错"); }else { fgets(s1,256,f1); printf("%s ",s1); } fclose(f1); f2=fopen("share.txt","r"); if (!f2) { perror("打开出错"); }else { fgets(s2,256,f2); printf("%s ",s2); } //关掉指针 fclose(f2); getchar(); getchar(); return 0; }
struct mytime { //char name[256]; int hour;//时 int min; //分 int sec; //秒 }; typedef struct _stu_data { char name[256];//学生名字 int sex;//0女生,非0表男生 struct mytime stuTime;//签到时间 struct stu_data* front; //指向前一个结点 struct stu_data* back; //指向后一个结点 } ; typedef union test1 { char i; int j; float k; }test; typedef int (*pn[2])(int,int,int); //typedef int (*padd)(int ,int ,int); typedef struct _stu_data stu_data; struct _stu_data stu; stu_data stu2; //struct _stu_data stu2; test tt1; //union test1 tt1; typedef int *p; p p1;// int * p;