输入输出函数(C和指针第15章)
输入输出函数(C和指针第15章)
1错误报告
函数:void perror(char const*message)
用于打印错误信息,相当于C++中的cerror,如下例:
If (fclose(filename)!= 0)
{
perror("fclose error");
};
如果文件读取失败就会打印上述字符串,然后跟一个分号和一个空格,最后打印相关错误的系统信息。
2 打开流
函数:FILE *fopen(char const*filename,char const *mode)
对于打开模式(mode)有:
读取
写入
添加
文本
r
w
a
二进制
rb
wb
ab
1) 以读的模式打开文件,那么文件必须存在;
2) 以写的模式打开的话,若文件不存在则新建;若文件存在则清空;
3) 以添加的模式打开文件,若不存在新建;若存在则从文件末尾开始添加;
4) 若以“a+”模式打开文件,那么表示可读写,当你写完一些数据之后想读数据,或者读完数据想写一些数据时,你一般必须借助(fseek,fsetpos,rewind)重新定位文件读写的当前位置。
5) 你总应该检查文件打开是否成功。
函数:FILE * freopen ( const char *filename, const char * mode, FILE * stream )
功能:实现重定向,把流stream重定向到filename,一般流stream会用stdin,stdout或者stderr。
使用方法:因为文件指针使用的是标准流文件,因此我们可以不定义文件指针。
接下来我们使用freopen()函数以只读方式r(read)打开输入文件slyar.in
freopen("slyar.in","r", stdin);
然后使用freopen()函数以写入方式w(write)打开输出文件slyar.out
freopen("slyar.out","w", stdout);
接下来的事情就是使用freopen()函数的优点了,我们不再需要修改scanf和printf,而是维持代码的原样就可以了。因为freopen()函数重定向了标准流,使其指向前面指定的文件。
最后只要使用fclose关闭输入文件和输出文件即可。
fclose(stdin);
fclose(stdout);
若要恢复句柄,可以重新打开标准控制台设备文件,只是这个设备文件的名字是与操作系统相关的。
DOS/Windows:
freopen("CON","r", stdin);
Linux:
freopen("/dev/console","r", stdin);
下面看一个例子,标准输入stdin 重定向到in.txt,标准输出重定向到out.txt中:
#include<stdio.h>int main(){ freopen("out.txt","r",stdin); freopen("in.txt","w",stdout); char c; while(scanf("%c",&c) != EOF) { printf("%c",c); }}
该函数的功能就相当于把文件out.txt的内容复制到in.txt中。
顺带提下int fclose(FILE *stream),就不细讲了。
3 字符I/O
函数:
1) int getchar(void)
2) int getc(FILE *stream)
3) int fgetc(FILE *stream)
三个函数都是从流中读取字符,但是3)只能从标准输入中读取。读取失败返回EOF 。1)2)本质上是宏。
函数:
1) int putchar(int c)
2) int putc(int c,FILE*stream)
3) int fputc(int c,FILE*stream)
与上面的函数基本同理。1)2)本质上是宏。
一个小工具:
函数:int ungetc(int c,FILE *stream)
把一个先前读取的字符退回到流中,这样它可以在以后被重新读入。退回并不影响流指针所指向的文件内容,而是改变读取的当前位置。
4 未格式化的行I/O
行I/O可以用两种方式执行——未格式化的或者格式化的。这两种形式都用于操纵字符串。区别在于未格式化的I/O简单读取或写入字符串,而格式化的I/O则执行数字和其它变量的内部和外部表示直接的转换。
1 gets && puts家族
1) char *fgets(char *buffer,int buffer_size,FILE*stream)
2) char *gets(char *buffer)
3) int *fputs(char const *buffer,FILE *stream)
4) int *puts(char const *buffer)
1) fgets函数读取流的一行到缓冲区buffer中(包括换行符‘\n‘),若超出buffer_size的大小,则读取行的一部分,下次继续读取剩余部分。返回值为指向buffer的指针,且在buffer指向缓冲区末尾添加‘\0‘使其成为一个字符串。若达到文件末尾则返回NULL。
2) fputs中buffer不能为空,必须要包含字符串,buffer必须以NUL(\0)结尾,可以一次读入一行的一部分,可以一次一行,也可以一次多行。若写入错误,fputs返回常量值EOF。
3) gets和puts函数几乎同fgets与fputs相同。区别在于,他们的流是标准输入输出流。其次gets读取一行时并不在缓冲区存储换行符。Puts函数写入时他在字符串写入标准输出后,再添加一个换行符。
4) 由于gets函数没有缓冲区大小,很容易造成缓冲区溢出,导致写入写入溢出,可能会破坏一个或多个相关变量的值,所以一般不推荐使用。
5 格式化的行I/O
“格式化的行I/O”这个名字从某种意义上来讲是不准确的,因为scanf和printf家族并不局限于单行,他们同样可以在行的一部分或者多行上进行I/O操作。
1 scanf家族
1) int fscanf(FILE *stream,char const*format,...)
2) intscanf(char const *format,...)
3) int sscanf(char const *string,charconst *format,...)
与2)用法基本一致,1)是从指定流读取,2)是从标准输入读取,3)是从字符串读入。
2printf家族
1) int fprintf(FILE *stream,char const*format,...)
2) int printf(char const *format,...)
3) int sprintf(char *buffer,char const*format,...)
6 二进制I/O
把数据写到文件效率最高的方法是用二进制形式写入。二进制数出可避免在数值转换过程中所涉及的开销和精度损失。但二进制数据并非人眼所能阅读,所以这个技巧只有当数据将被另一个程序按顺序读取时才能使用。
fread函数用于读取二进制数据,fwrite函数用于写入二进制数据。原型如下:
size_t fread(void *buffer,size_t size,size_t count,FILE *stream)
size_t fwrite(void *buffer,size_t size,size_tcount,FILE *stream)
解释:
buffer是一个用于保存数据的缓冲区,size是缓冲区中每个元素所占字节数,count是读取或写入的元素个数,stream是数据读取或写入的流。
7刷新和定位函数
无论是输入还是输出都不会是立即执行,它们都会向文件立即写入,而是先存入缓冲区中,到一定时机再进行写入。有时我们可以借助fflush函数进行缓冲区强行刷新,同时将内容写入流中。
int fflush(FILE *stream);
一般我们读取文件或写入文件都是顺序的(线性的),但有的时候我们也需要随机访问,这时候我们可以使用下面的工具函数:
long ftell(FILE *stream);
int fseek(FILE *stream,long offset,int from);
1) ftell返回文件读写的当前位置。fseek允许定位到文件中的指定位置,具体有一些其它影响,此不赘述。
另外还有三个额外的函数,用一些限制更加严格的方式执行相同任务。它们的原型如下:
void rewind(FILE *stream)
int fgetpos(FILE *stream,fpos_t *position)
int fsetpos(FILE *stream,fpos_t const *position)
rewind函数将读/写指针设置回指定流的起始位置。它同时清除流的错误提示标志。Fgetpos和fsetpos函数分别是ftell和fseek函数的替代方案。
它们的主要区别在于这对函数接受一个指向fpos_t的指针作为参数。fgetpos在这个位置存储文件的当前位置,fsetpos把文件设置为存储在这个位置的值。
用fpos_t表示一个文件位置的方式并不是由标准定义的。它可能是文件中的一个字节偏移量,也可能不是。因此,使用一个从fgetpos函数返回的fpos_t类型的值是唯一安全的用法是把它作为参数传递给后续的fsetpos函数。
8改变缓冲方式
void setbuf(FILE*stream,char *buf)
int setvbuf(FILE *stream,char *buf,int mode,size_t size)
9 流错误函数
下面这些函数用于判断流的状态:
int feof(FILE*stream)
int ferror(FILE *stream)
void clearerr(FILE *stream)
如果流当前处于文件尾,那么feof函数返回真。若文件出现任何读写错误,ferror返回真,其实用来报告流错误的状态的。最后,clearerr是用来对指定流的错误标志进行重置的。
10 临时文件&&文件操作
FILE *tmpfile(void)
该函数创建一个临时文件并返回指向它的指针,当文件被关闭或者程序终止时这个文件便自动删除。该文件以wb+模式打开,可用于二进制和文本数据。
char *tmpnam(char *name)
用于产生临时文件名。
int remove(charconst *filename);
int rename(char const *oldname,char const *newname);
remove函数删除一个指定的文件,当被remove的文件处于打开状态时,那么结果取决编译器。
rename函数用于改变一个文件的名字,如果已经有一个newname存在的话,那么结果取决于编译器。