参考资料:c primer plus
目录
1.int main(int argc,char*argv[])
5.fseek()与ftell(),以及fgetpos()和fsetpos()
7.int feof(FILE*fp)和int ferroe(FILE*fp)
一、文件
1.流(stream)和文件(file):
(1)文件
文件通常是磁盘或固态硬盘上一段以命名的存储区。例如:stdio.h,还有你所写的c程序。
C语言把文件看作是一系列连续的字节,每个字节都能被单独读取。
C 语言提供两种文件方式:文本模式和二进制模式。
(2)流
流是字节序列的抽象概念,例如文件、输入/输出设备、内部进程通信管道等。流提供一种向后备存储器写入字节和从后备存储器读取字节的方式。
流是一个逻辑设备,和文件有着相同的行为。
2.文件指针FILE
它是typedef定义的,如果有兴趣,可以去了解。
它是一个结构指针,是一个新的数据类型,是一个包含文件管理数据的结构指针,在打开一个文件之前必须定义一个文件指针。
二、标准I/O函数
1.int main(int argc,char*argv[])
argc表示argv中存放string的个数。argc的值是获取命令行参数的,一般情况下,argc的值为1(你只运行该程序,没有写入其他文件时)。
argv是一个指针数组,它存储的是各命令行参数 。
//这里主要说linux,因为我使用的就是linux
#include<stdio.h>
int main(int argc,char*argv[]){
printf("%d\n",argc);//1
for(int i=0;i<argc;i++){
printf("%s\n",argv[i]);//程序名称
}
return 0;
}
现在我们打开终端(windows则按win+r输入cmd,打开那个熟悉的黑框)。
//首先记得编译该程序,windows运行该程序
//linux找到该文件所处位置
//我这个文件叫test
//输入
./tese 123 hello world
就会出现这些东西了,可以看见argc=4 , 123,hello,world则分别是argv[1],argv[2],argv[3]
记得是运行test,而不是test.c
2.exit()与return
exit()函数是关闭所有打开的文件并结束程序,正常结束会传递0,异常结束程序传递其他非零值,不同退出值可用于区分退出原因:
比如:
if((fp=(fopen(test,"r"))==NULL){//这些函数下面会讲
exit(1)
}
if(fclose(fp)!=0){
exit(2)
}
如果你在一个函数中使用exit则会关闭程序,而非跳出该函数.
而如果你在一个非main函数中使用return则会跳出该函数,在main函数中使用return则会跳出程序。
return会将控制权交给上一级的递归。
也就是说在main函数中return 0;
与 exit(0);作用等同。
stdlib.h头文件中 定义了两个变量:
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
3.fopen()与fclose()
(1)fopen()
fopen()的作用是打开文件声明在stdio.h中
原型为
FILE *fopen(char *filename, *type);
第一个参数是待打开的文件的名称,更具体地说是一个包含改文件名的字符串地址。
第二个参数是一个字符串,制定待打开文件的模式。
模式字符串 含义
——————————————————————————————————————————————————————————————————————————————————————
"r" 打开文字文件只读
"w" 以写模式打开文件,并把先有文件长度截为0(删除文件()),如果文件不存在,则创建一新文件
"a" 以写模式打开文件,在原有文件后面添加内容, 如果文件不存在则创建一个
"r+" 以更新模式打开文件(打开一个文字文件读/写)
"w+" 以更新模式打开文件,并把先有文件长度截为0,如果文件不存在,则创建一新文件
"a+" 以更新模式打开文件,在原有文件后面添加内容, 如果文件不存在则创建一个,可以读文件,但只能在文件末尾补充
"b" 二进制文件(可以和上面每一项合用)(如:"rb","rb+")
"x" 可以和上面每一项合用,(c11)类似非x模式,但如果文件已存在或以独占模式打开文件,则会失败
—————————————————————————————————————————————————————————————————————————————————————
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char*argv[]){
FILE *fp;
if((fp=fopen(argv[1],"r"))==NULL){
exit(EXIT_FAILURE);//EXIT_FAILURE是一个宏,为1
}
fclose(fp);//关闭文件
return 0;
}
程序成功打开文件后,fopen()将返回文件指针,其他I/O函数可以用该指针处理这个文件。
文件指针并不指向实际的文件,而是指向一个包含文件信息的数据对象,其中包含操作文件的I/O函数所用的缓冲区信息。
注意:同一时间打开的文件数是有限的。
(2)fclose()
fclose()的作用是关闭fp指向的文件.
函数原型:
fclose(FILE *fp)
if(fclose(fp)!=0){
exit(2);
}//关闭文件
fclose如果关闭成功,将返回一个0,否则返回EOF
2.putc()与getc()
putc()和gets()与getchar()和putchar()类似,但有所不同的一点是,前者需要告诉使用哪一个文件,后者默认输入输出设备(键盘和显示屏)。
ch=getchar() 等效于 ch=getc(stdin)
putc(ch,stdout) 等效于 putchar(ch)
实际上,putchar()和getchar()通过putc()和getc()定义
3.fprintf()与fscanf()
(1)fprintf
将argument内各项的值,按format(格式控制字符串)所表示的格式,将数据格式为字符串的形式写入到文件指针fp指向的文件中。
fprint() 的函数原型为
int fprintf( FILE *stream, const char *format, [ argument ]…)
作用与printf()类似
fprintf()是将内容输入到stream中
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char*argv[]){
FILE *fp;
if((fp=fopen(argv[1],"w+"))==NULL){
exit(EXIT_FAILURE);
}
fprintf(fp,"hello");//将“hello”发送到fp指向的文件中
fprintf(stdout,"hello");//将“hello”发送到输出设备(显示屏)
fclose(fp);
return 0;
}
(2)fscanf()
fscanf()的函数原型为:
int fscanf(FILE* stream, const char* format, [argument...]);
从文件指针fp指向的文件中,按format中对应的控制格式读取数据,并存储在[argument...]对应的变量中;
fscanf 函数与 scanf 类似,只不过前者用于读取文件流的数据。
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char*argv[]){
FILE *fp;
char s1[100];
if((fp=fopen(argv[1],"a+"))==NULL){
exit(EXIT_FAILURE);
}
fprintf(fp,"hello");//将“hello”发送到fp指向的文件中
fprintf(stdout,"hello\n");//将“hello”发送到输出设备(显示屏)
rewind(fp);//将光标移动回文件开头
fscanf(fp,"%s",&s1);//将fp指向的文件的信息发送s1
fprintf(stdout,"%s\n",s1);//将s1中信息发送到输出设备
fclose(fp);
return 0;
}
4.fgets()和fputs()
(1)fgets()
fgets()的函数原型是:
char * fgets(char * s, int n,FILE *stream);
s为储存输入位置的地址,n为字符串大小,stream为指向FILE的指针(待读文件)
fgets()函数读取输入知道第一个换行符的后面,或者读到文件结尾,或者读n-1个字符。
fgets会在末尾添加一个“\0”使之成为一个字符串。
fgets()在读到EOF时将返回NULL;如果没有则返回之前传给它的第一个参数指针;当n<=0 时返回NULL,即空指针;当n=1 时,返回空串""。
(2)puts()
puts()的函数原型为:
int fputs(const char *s, FILE *stream);
s为字符串的地址,stream为文件指针。
该函数的作用是跟据传入地址找到的字符串写入指定的文件中。
注意:fputs()在打印时不会在末尾加换行符。
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char*argv[]){
char s1[100];
FILE *fp;
if((fp=fopen(argv[1],"a+"))==NULL){
exit(EXIT_FAILURE);
}
fgets(s1,100,fp);//将fp指向的文件中的字符传给s1
fputs(s1,stdout);//s1中字符打印在stdout上(输出设备)
return 0;
}
5.fseek()与ftell(),以及fgetpos()和fsetpos()
(1)fseek()
函数原型:
int fseek(FILE *stream, long offset, int fromwhere);
fseek的作用是将fopen打开的文件直接移动到任意字节处。
第一个参数stream为文件指针
第二个参数offset为偏移量,整数表示正向偏移,负数表示负向偏移
第三个参数origin设定从文件的哪里开始偏移,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET:
SEEK_SET: 文件开头
SEEK_CUR: 当前位置
SEEK_END: 文件结尾
其中SEEK_SET,SEEK_CUR和SEEK_END和依次为0,1和2. `
(2)ftell()
函数原型:
long ftell(FILE* stream);
ftell的作用是获取文件流的读取位置。
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char*argv[]){
FILE *fp;
char s1[100];
char ch;
long n=0;
long count=0;
if((fp=fopen(argv[1],"r+"))==NULL){
exit(EXIT_FAILURE);
}
while((ch=getchar())!=EOF){
putc(ch,fp);
}
fseek(fp,0L,SEEK_END);//将光标移动到文件结尾
n=ftell(fp);//获取从文件开头到结尾的所有字节数
fseek(fp,0L,SEEK_SET);//将光标移动到文件开头
while((ch=getc(fp))!=EOF){
putc(ch,stdout);
count++;
}
printf("\nftell(fp)=%d\n",n);
printf("%d char\n",count);
fclose(fp);
return 0;
}
这个程序的目的是获取你一共向文件中写了多少个字符。
(3)fgetpos()和fsetpos()
fseek()和ftell()的长度为long,但目前文件越来越大,long已无法满足需求,因此,ANSIC新增了fgetpos()和fsetpos(),这两个新定位函数采用了新类型:fpos_t类型,(file position type),但fpos_t不是基本类型,它由其他类型来定义。fpos_t类型的变量或数据对象可以在文件中指定一个位置,它不能是数组结构。
int fgetpos(FILE* restrict stream,fpos_t * restrict pos);
//把fpos_t类型的值放在pos指向的位置上。
//当前位置和文件开头的距离
//成功返回0,失败返回非0
int fsetp[os(FILE *stream,const fpos_t *pos);
//使用pos指向的位置上的fpos_t类型值来设置文件指针指向的偏移该值后的位置。
//成功返回0,失败返回非0
//fpos_t类型的值应该通过调用fgetpos()来获得
6.fwrite()和fread()
(1)fwrite()
函数原型:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
fwrite()通常把二进制数值写入文件。
ptr是待写入数据块的地址。
size表示待写入的数据块的大小,单位为字节。
nmemb表示待写入数据块的数量,每个数据块的大小为 size 字节。
stream是指定待写入的文件。
FILE *fp;
char s1[100];
fwrite(s1,100,1,fp);//将s1的内容写入fp指向的文件
`fwrite会返回成功写入的项的数量,正常情况下就是nemmb.
(2) fread()
函数原型:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
ptr是待读文件数据在内存上的地址。
size – 这是要读取的数据块的大小,单位为字节。
nmemb – 这是待读入数据块的个数,每个数据块的大小为 size 字节。
stream – 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。
char s1[100];
fread(s1,100,1,fp);
//读取上次写入的100个字符
7.int feof(FILE*fp)和int ferroe(FILE*fp)
一般情况下函数返回EOF,则通常表示函数已经到达文件结尾。但是当文件读取错误时,函数也会返回EOF,为了区分这种情况,就有了这两个函数‘
fefo()函数返回一个非0值时表示达到文件结尾,否则返回0.
ferror()函数返回一个非0值时,表示读写错误,否则返回0.
8.rewind()
表示返回文件开头。
函数原型
void rewind(FILE *stream);
与fseek(FILE*stream,0L,SEEK_SET)效果一样。
9.int ungetc(int c,FILE *fp)
把c指定的字符放回输入流,当下次调用标准输出时将读取该字符。
注意:如果放入多个字符,调用时读取方向将会与放入方向相反。
int main(){
char s1[20]="hello world";
char ch;
int i=0;
while((ch=s1[i])!='\0'){
if(i>=6){
ungetc(ch,stdin);
break;
}
putchar(ch);
i++;
}
ch=getc(stdin);
putchar(ch);
printf("\n");
return 0;
}
根据ungetc来说,应该输出"hello world",但实际上只输出了"hello w",我便进行了以下测试:
int main(){
char s1[20]="hello world";
char ch;
int i=0;
while((ch=s1[i])!='\0'){
if(i>=6){
ungetc(ch,stdin);
break;
}
putchar(ch);
i++;
}
ch=getc(stdin);
putchar(ch);
ch=getc(stdin);
putchar(ch);
if(!feof(stdin)){
printf("error\n");
}
printf("\n");
return 0;
}
结果是还是输出“hello w”后等待输入,我猜测可能是因为标准输入流stdin无法使用ungetc放回任何字符,标准输入stdin只支持从键盘输入字符;
10.fflush()
函数原型
int fflush(FILE* fp);
fflush()的作用是引起输出缓冲区中所有未写入的数据,发送到fp所指定的输出文件。这个过程就是刷新缓冲区,如果fp为空指针,则刷新所有输出缓冲区。
11.setvbuf()
函数原型:
int setvbuf(FILE * fp, char * buf, int mode, size_t size);
它的作用是创建一个供I/O函数替换使用的缓冲区,在打开文件后且未对流操作时使用此函数。
fp识别待处理的流。
buf指向待使用的存储空间,如果buf值不为NULL,则必须创建一个缓存区。
mode:
_IOFBF:完全缓冲区(在缓冲区满时刷新);
_IOLBF:行缓冲(在缓冲区满或者写入一个换行符时)
_IONBF:无缓冲
操作成功返回0,否则返回非0.
FILE*fp;
if((fp=fopen(argv[1],"r+"))==NULL){
fprintf(stderr,"Error");
exit(EXIT_FAILURE);
}
if((setvbuf(fp,NULL,_IOFBF,2048))!=NULL){
fprintf(stderr,"Error");
exit(EXIT_FAILURE);
}