文件是当今计算机系统不可或缺的一部分.文件用于存储程序、文档、数据、书信、表格、图形、照片、视频、和许多其他种类的信息。作为程序员,必须会编写创建文件和从文件读写数据的程序。接下来将对文件进行简述。
文本文件和二进制文件的区别是什么???
文本文件和二进制文件就其存放内容而言,均为二进制形式(0或1)存储。但是,对于文本文件而言,其最初使用二进制编码的字符(例如ASCII或Unicode)表示文本,其中包含文本内容;而对于二进制文件而言,其二进制值代码机器语言代码或数值数据或图片或音乐编码,其中包含二进制内容。
文本模式和二进制模式的区别是什么???
关于这个问题,可以参考下面这篇博客的讲解:
https://blog.csdn.net/zrf2112/article/details/51996003
下面我们对一些标准I/O函数进行介绍。
<1>fopen()函数
函数原型:
#include<stdio.h>
FILE *fopen(const char *filename,const char *mode);
参数说明:
filename:表示欲打开的文件路径及文件名;
mode:一个字符串,指定代打开文件的模式。
详细的模式字符串如下表格所示:
模式字符串 | 含义 |
“r” | 以只读模式打开文件 |
“w” | 以写模式打开文件,把现有文件的长度截为0,如果文件不存在,则创建一个新文件。 |
“a” | 以写模式打开文件,在现有的文件末尾添加内容,如果文件不存在,则创建一个新文件。 |
“r+” | 以更新模式打开文件(即可以读写文件)。 |
“w+” | 以更新模式打开文件(即,读和写),如果文件存在,则将其长度截为0;如果文件不存在,则创建一个新的文件; |
“a+” | 以更新模式打开文件(即,读和写),在现有文件的末尾添加内容;如果文件不存在,则创建一个新的文件;可以读整个文件,但是只能从文件末尾添加内容。 |
“rb”、“wb”、“ab”、“rb+”、“r+b”、“wb+” | 与上一个模式对应,但是是以二进制模式而不是以文本模式打开文件 |
返回值:程序调用成功,返回一个非空的文件指针,调用失败,返回NULL。
例子:
#include<stdio.h>
int main()
{
char *path = "E://a.txt";
FILE *pf = fopen(path,"r"); //以只读形式打开文件
if(NULL == pf)
{
printf("Don't open the file!\n");
exit(EXIT_FAILURE);
}
fclose(pf); //关闭文件
return 0;
}
<2>getc()函数
函数原型:
#include<stdio.h>
int getc(FILE *stream);
功能:用函数getc从文件读取字符。getc()函数与getchar函数类似。所不同的是,要告诉getc函数使用哪一个文件。
例如:从标准输入中获取一个字符”:ch = getchar();
从fp指定的文件中获取一个字符":ch = getc(fp);
返回值:读取失败或者到了文件结束标志返回EOF。
<3>pusc()函数
函数原型:
#include<stdio.h>
int putc(int c,FILE *stream);
功能:在fp所指向的文件的当前读写位置写入一个字符。putc()函数与putchar()函数类似。所不同的是,putc()函数使用哪一个文件。
例如: 从标准输出中获取一个字符":putchar();
把字符ch放入FILE指针fp指定的文件中":putc(ch,fp);
返回值:写入字符成功则函数返回值为该字符的ASCII值,写入字符不成功则返回值为EOF。
<4>flcose()函数
函数原型:
#include<stdio.h>
int close(FILE *stream);
功能:fclose(fp)函数关闭fp指定的文件。
返回值:调用成功返回0,调用失败返回EOF。
<5>fprintf()和fscanf()函数
函数原型:
#include<stdio.h>
int fprintf(FILE *stream,const char *format,...);
int fscanf(FILE *stream,const char *format,...);
参数说明:
stream:文件指针
format:输出格式
功能:fprintf()和fscanf()函数工作方式和printf()和scanf()类似,区别在于前者需要第一个参数指定一个待处理的文件。
<6>sprintf()和sscanf()函数
函数原型:
#include<stdio.h>
int sprintf(char *s,const char *format,...);
int sscanf(const char *s,const char *format,...);
功能:fprintf()和fscanf()函数工作方式和printf()和scanf()类似,区别在于前者需要第一个参数指定一个待处理的字符串。
<7>fgets()函数
函数原型:
#include<stdio.h>
char *fgets(char *buf, int bufsize, FILE *stream);
参数说明:
buf: 字符型指针,指向用来存储所得数据的地址。
bufsize: 整型数据,指明存储数据的大小。
stream: 文件结构体指针,将要读取的文件流。
功能:从文件结构体指针stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋'\0'),如果文件中的该行,不足bufsize-1个字符,则读完该行就结束。如若该行(包括最后一个换行符)的字符数超过bufsize-1,则fgets只返回一个不完整的行。
返回值:成功,则返回第一个参数buf;如果发生读入错误,error指示器被设置,返回NULL,buf的值可能被改变。
<8>fputs()函数
函数原型:
#include<stdio.h>
int fputs(const char *str, FILE *stream);
功能:把字符串写入到指定的流( stream) 中,但不包括空字符。
参数说明:
str:这是一个数组,包含了要写入的以空字符终止的字符序列。
stream:指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流
返回值:该函数返回一个非负值,如果发生错误则返回 EOF。
<9>fflush()函数
函数原型:
#include<stdio.h>
int fflush(FILE *stream)
功能:清除读写缓冲区,需要立即把输出缓冲区的数据进行物理写入时。如果参数stream 为NULL,fflush()会将所有打开的文件数据更新。
返回值:如果成功刷新,fflush返回0。指定的流没有缓冲区或者只读打开时也返回0值;否则返回EOF。
<10>ungetc()函数
函数原型:
#include<stdio.h>
int ungetc(int c, FILE *stream);
参数说明:
c: 要写入的字符;
stream:文件流指针,必须是输入流不能是输出流
功能:把c指定的字符放回输入流中
返回值:操作成功返回字符c, 操作失败返回EOF。
<11>ftell()函数
函数原型:
#include<stdio.h>
long ftell(FILE *stream);
参数说明:
stream:FILE指针,指向待查找的文件;
offset:偏移量,表示从起始点开始要移动的距离;
fromwhere:起始点模式,该参数确定了起始点;
几种起始点模式如下表格所示:
模式 | 偏移量的起始点 |
SEEK_SET | 文件开始处 |
SEEK_CUR | 当前位置 |
SEEK_END | 文件末尾 |
功能:用于得到文件位置指针当前位置相对于文件首的偏移字节数。fell()函数一般和fseek()函数一起使用。
说明:由于返回值是long类型,而long类型的取值存在范围,故当文件大小大于2.1G时可能会出现错误。
<12>fseek()函数
函数原型:
#include<stdio.h>
int fseek(FILE *stream, long offset, int fromwhere);
功能:重定位流(数据流/文件)上的文件内部位置指针。
例如:
fseek(fp ,0L , SEEK_SET); //定位至文件开始处
fseek(fp , 10L, SEEK_SET); //定位至文件中的第10个字节
fseek(fp , 2L, SEEK_CUR); //从文件当前位置前移2个字节
fseek(fp , -10L, SEEK_END); //从文件结尾处回退10个字节
<13>fgetpos()和fsetpos()函数
函数原型:
#include<stdio.h>
int fgetpos(FILE * restrict stream,fpos_t * restrict pos);
int fsetpos(FILE *stream, const fpos_t *pos);
功能:fseek()和ftell()存在的问题就是,他们都把文件限制在long类型能表示的范围内。这个大小可能不能满足满足人们对于文件操作的需求。所以,产生了两个新的函数:fgetpos()和fsetpos()函数,这两个函数没有使用long,而是使用了fpos_t类型,他不是一个基本类型,而是根据其他类型定义的。
返回值:成功返回0,失败返回非0。
例子:
int main()
{
FILE* stream;
char string[]="This is a test";
fpos_t filepos;
fpos_t filepos2 = 3;
stream = fopen("E:\\a.txt","w+");
fwrite(string,strlen(string),1,stream);
/*report the file pointer position*/
fgetpos(stream,&filepos);
printf("The file pointer is at byte:\%ld\n",filepos);
fsetpos(stream,&filepos2);
fgetpos(stream,&filepos);
printf("The file pointer is at byte:\%ld\n",filepos);
fclose(stream);
return 0;
}
<14>fread()函数
函数原型:
#include<stdio.h>
size_t fread ( void *buffer, size_t size, size_t count, FILE *stream) ;
参数解释:
buffer:用于接收数据的内存地址;
size:要读的每个数据项的字节数,单位是字节;
count:要读count个数据项,每个数据项size个字节;
stream:输入流
功能:fread是一个函数,它从文件流中读数据,最多读取count个项,每个项size个字节,如果调用成功返回实际读取到的项个数(小于或等于count),如果不成功或读到文件末尾返回 0。
返回值:返回真实读取的项数,若大于count则意味着产生了错误。
<15>fwrite()函数
函数原型:
#include <stdio.h>
size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);
参数解释:
buffer:是一个指针,对fwrite来说,是要获取数据的地址;
size:要写入内容的单字节数;
count:要进行写入size字节的数据项的个数;
stream:目标文件指针;
返回值:返回实际写入的数据项个数count。
<16>setvbuf()函数
函数原型:
#include<stdio.h>
int setvbuf(FILE *stream, char *buf, int type, unsigned size);
参数说明:
type : 期望缓冲区的类型:
- _IOFBF(满缓冲):当缓冲区为空时,从流读入数据。或者当缓冲区满时,向流写入数 据。
- _IOLBF(行缓冲):每次从流中读入一行数据或向流中写入一行数据。
- _IONBF(无缓冲):直接从流中读入数据或直接向流中写入数据,而没有缓冲区。
size : 缓冲区内字节的数量。
功能:用于设定文件流的缓冲区。
<17>feof()和ferror()函数
函数原型:
#include<stdio.h>
int feof(FILE *fp);
int ferror(FILE *fp);
功能:如果标准输入函数返回EOF,则通常表明函数已达到文件末尾。然而,出现读取错误时,函数也会返回EOF。feof()和ferror()函数用于区分两种情况。当上一次输入调用检查到文件末尾时,feof()函数返回一个非零值,否则返回0.当读或者写发生错误,ferror()函数返回一个非零值,否则返回0。
函数应用示例:
1.将桌面上的一个.txt文件拷贝到E:中;
代码实现:
#include<stdio.h>
#include<stdlib.h>
int main()
{
char *path = "E:\\C++.png";
char *path2 = "C:\\Users\\lenovo\\Desktop\\STL二级空间配置器.png";
FILE *pr = fopen(path2,"rb");
FILE *pw = fopen(path,"wb");
if(NULL == pr)
{
printf("1not open the file!\n");
}
if(NULL == pw)
{
printf("2not open the file!\n");
}
char buff[1024] = {0};
while(fread(buff,1,1024,pr) > 0)
{
fwrite(buff,1,1,pw);
}
fclose(pr);
fclose(pw);
return 0;
}
2.//把一系列文件的内容附加到另外一个文件的末尾;
代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define BUFSIZE 4096
#define SLEN 81
void append(FILE *source,FILE *dest)
{
size_t bytes;
static char temp[BUFSIZE];
while((bytes = fread(temp,sizeof(char),BUFSIZE,source)) > 0)
{
fwrite(temp,sizeof(char),bytes,dest);
}
}
char *s_gets(char *st,int n)
{
char *ret_val;
char *find;
ret_val = fgets(st,n,stdin);
if(ret_val)
{
find = strchr(st,'\n');
if(find)
{
*find = '\0';
}
else
{
while(getchar() != '\n')
{
continue;
}
}
return ret_val;
}
}
int main()
{
FILE *fa,*fs; //fa指向目标文件,fs指向源文件
int files = 0; //附加的文件数量
char file_app[SLEN]; //目标文件名
char file_src[SLEN]; //源文件名
int ch;
puts("Enter name of destination file:");
s_gets(file_app,SLEN);
if((fa = fopen(file_app,"a+")) == NULL) //打开目标文件
{
fprintf(stderr,"Can't open %s\n",file_app);
exit(EXIT_FAILURE);
}
if(setvbuf(fa,NULL,_IOFBF,BUFSIZE) != 0)
{
fputs("Can't create output buffer\n",stderr);
exit(EXIT_FAILURE);
}
puts("Enter name of first source file(empty line to quit):");
while(s_gets(file_src,SLEN) && file_src[0] != '\0')
{
if(strcmp(file_src,file_app) == 0) //防止程序把文件附加在自身末尾
{
fputs("Can't append file to itself\n",stderr);
}
else if((fs = fopen(file_src,"r")) == NULL) //以只读形式打开源文件
{
fprintf(stderr,"Can't open %s\n",file_src);
}
else
{
if(setvbuf(fs,NULL,_IOFBF,BUFSIZE) != 0)
{
fputs("Can't create output buffer\n",stderr);
continue;
}
append(fs,fa);
if(ferror(fs) != 0)
{
fprintf(stderr,"Error in reading file %s.\n",file_src);
}
if(ferror(fa) != 0)
{
fprintf(stderr,"Error in writing file %s.\n",file_app);
}
fclose(fs);
files++;
printf("File %s appended.\n",file_src);
puts("Next file (empty line to quit):");
}
}
printf("Done appending.%d files appended.\n",files);
rewind(fa);
printf("%s contents:\n",file_app);
while((ch = getc(fa)) != EOF)
{
putchar(ch);
}
puts("Done displaying");
fclose(fa);
return 0;
}