- 错误报告
void perror(char const *message);
perror函数打印出这个字符串,后面跟一个分号和一个空格,然后打印出一条用于解释errno当前错误代码的信息。
2.终止执行
void exit(int status);
定义于stdlib.h,status返回给操作系统。预定义符号EXIT_SUCCESS,
EXIT_FAILURE分别提示程序的终止是成功还是失败。可以在调用perror之后调用exit终止程序
- 没有返回值:当exit函数结束时,程序已经消失,所以他无处可返。
3.I/O概念
1. 流
- 在stdio.h中
- 绝大多数流是完全缓冲的:“读取”、“写入”实际是从一块被称为缓冲区(buffer)的内存区域来恢复至数据。
- 用于输出流的缓冲区只有当它写满时才会被刷新(flush,物理写入)到设备或文件中,一次性把写满的缓冲区写入比逐片把程序产生的输出分别写入效率高。类似,输入缓冲区当它为空时通过从设备或文件读取下一块较大的输入,重新填充缓冲区。
- 常见调试策略是:调用printf函数,确定错误出现的具体位置,但这些函数调用的输出结果被写入到缓冲区中,并不立即显示于屏幕上。If
程序失败,缓冲输出可能不会被实际写入,得不到正确的出错位置。解决方法:
printf("something or other");
fflush(stdout); //在每个用于调试的printf函数之后立即调用fflush,
//迫使缓冲区的数据立即写入,不管他是否已满。
流分为两种类型,文本(text)流和二进制(binary)流:
一. 文本流
二. 二进制流 完全根据程序编写他们的形式写入到文件或设备中,而且完全根据他们从文件或设备读取的形式读入到程序中,并未做任何改变。
2. 文件
- FILE数据结构,用于访问一个流。每个流有一个对应FILE与它关联。
- 运行程序时,系统提供至少三个流:标准输入(stdin)、标准输出(stdout)、标准错误(stderr)。均为指向FILE结构的指针
- 默认标准输入是键盘设备,标准输出为终端or屏幕,可以对输入/输出进行重定向
- 标准错误和标准输入默认是一样的,perror函数也把它的输出写到这个地方。但是,为错误信息准备一个不同的流意味着,即使标准输出重定向到其他地方,错误信息仍将出现在屏幕或其它缺省的输出设备上。
3. 标准I/O常量
EOF:函数的返回值,提示到达了文件尾。EOF实际值比一个字符要多几位,为了避免二进制值被错误地解释为EOF
FOPEN_MAX:一个程序最多能打开的文件数
FILENAME_MAX:整型值,提示一个字符数组应该多大以便容纳编译器所支持的最长合法文件名。
4. 打开流
FILE *fopen( char const *name, char const *mode);
打开一个特定的文件,并把一个流和这个文件相关联。name:希望打开的文件or设备的名字,mode:模式参数
------------- 读取 ------- 写入 ------- 添加 ---------------
文本 r w a
二进制 rb wb ab
注:
如果一个文件打开是用于写入的,如果他原先已经存在,那么它原来的内容就会被删除。
如果要添加的文件原先已存在,那么他原先的内容并不会被删除。
无论哪种情况,数据只能从文件的尾部写入。
mode为a+ 表示:该文件打开用于更新,并且流即允许读也允许写。但,如果已从文件中读了一些数据,开始写入数据之前,需要调用文件定位函数之一。如果已向文件写入一些数据,在读取文件数据之前,首先调用fflush函数 or 文件定位函数之一。
fopen函数执行成功,返回一个指向FILE结构的指针,代表这个新创建的流,执行失败,返回一个NULL指针,errno提示问题的性质。
freopen函数:
FILE *freopen( char const *filename, char const *mode, FILE *stream);
首先试图关闭这个流,然后用指定的文件和模式重新打开这个流,打开失败,返回NULL,成功,返回他的第三个参数值。
5. 关闭流
int fclose(FILE *f);
对于输出流,fclose函数在文件关闭之前刷新缓冲区。执行成功,返回0,否则返回EOF
6. 字符I/O
字符输入:
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void);
- 需要操作的流作为参数传递给getc、fgetc,getchar始终从标准输入读取。
- 每个函数从流中读取下一个字符,并把它作为函数的返回值返回,若流中没有更多的字符,返回EOF(因此返回值为int型而非char型)
字符输出:
int fputc(int character, FILE *stream);
int putc(int character, FILE *stream);
int putchar(int character);
失败返回EOF
撤销字符I/O:
int ungetc(int character, FILE *stream);
ungetc把一个先前读入的字符返回到流中,这样他可以在以后被重新读入。
eg:
/*
*把一串从标准输入读取的数字转换为整数
*/
int read_int()
{
int value, ch;
value = 0;
//转换从标准输入读入的数字,当我们得到一个非数字字符时就停止
while( (ch = getchar()) != EOF && isdigit(ch) )
{
value *= 10;
value += ch - '0';
}
//把非数字字符退回到流中,这样他就不会丢失
ungetc(ch, stdin);
return value;
}
7. 未格式化的行I/O
未格式化I/O:简单读取或写入字符串;格式化的I/O:执行数字和其他变量的内部和外部表示形式之间的转换。
//操作字符串(而非单个字符),处理一行行文本输入的程序中非常有用
char *fgets(char *buffer, int buffer_size, FILE *stream);
char *gets(char *buffer);
int fputs(char onst *buffer, FILE *stream);
int puts(char const *buffer);
fgets:
- 读取一个换行符,存储到缓冲区之后就不在读取
- 如果缓冲区内存储的字符数达到buffer_size - 1个时也停止读取,不会出现数据丢失情况,下一次调用fgets将从流的下一个字符开始读取。
- 任何情况下,一个NULL字节都将添加到缓冲区所存储数据的末尾,以使它成为一个字符串
- 在任何字符读取前就到达文件尾,缓冲区就未进行修改,fgets返回NULL指针(用于检查是否到达了文件尾)
fputs:
- 缓冲区中的字符串逐字写入,包括换行符(所以fputs既可以写入一行的一部分也可以写入多行)
- 出错返回EOF
while(fgets(buffer, MAX_LINE_LENGTH, input) != NULL)
fputs(buffer, output);
gets、puts:
gets读取一行输入时,不在缓冲区中存储结尾的换行符(注,没有缓冲区长度参数!)
puts:写入一个字符串后,向输出再添加一个换行符。
8. 格式化的行I/O
- scanf家族
int fscanf( FILE *stream, char const *format, ...);
int scanf( char const *format, ...);
int sscanf( char const *string, char const *format, ...);
根据format字符串给出的格式代码对它们进行转换,fscanf输入源:作为参数给出的流,scanf从标准输入读取,sscanf从第一个参数给出的字符串中读取字符。
scanf格式代码:
- 空白字符(与输入中的零个或多个空白字符匹配,在处理过程中将被忽略)
- 格式代码(指定函数如何解释接下来的输入字符)
格式代码都以一个百分号开头,后面可以是:
- 一个可选的星号(使转换后的值被丢弃而不是进行存储)
- 一个可选的宽度(限制将被读取用于转换的输入字符的个数,如未给出,函数连续读入字符直到空白字符)
- 一个可选的限定符(指定参数的长度)
nfields = fscanf(inputs, "%4d %4d %4d", &a, &b, &c);
//输入1 2则a=1,b=2,nfields=2
//输入12345 67890则a=1234,b=5,c=6789,nfields=3
代码 —— 参数 —————————含义———————
c ——— char * ————–读取和存储单个字符,前导的空白字符并不跳过,字符后面不添加NULL
u/o/x— unsigned * ——u:值被解释为十进制数,o:八进制,x:十六进制
s——— char * ———–读取一串非空白字符,发现空白时停止输入,字符串后面加NULL
[xxx]—– char * ———–当遇到第一个不在给定组合中出现的字符时,输入就停止。字符串后面自动加
——————————NULL([^abc]表示字符组合为a、b、c之外的所有字符)
- printf家族
int fprintf( FILE *stream, char const *format, ...);
int printf( char const *format, ...);
int sprintf( char *buffer, char const *format, ...);
printf结果输出送到标准输出
fprintf:可以使用任何输出流
sprintf:把它结果作为一个NULL结尾的字符串存储到指定的buffer缓冲区而不是写入流中(注,缓冲区大小!)
返回值均为实际打印or存储的字符数
format字符串可能包含格式代码:由一个百分号开头,后面可以跟零个或多个标志字符
-标志———–含义—————–
‘-’———–值在字段中左对齐,缺省情况下为右对齐
0 —————缺省情况下为使用空格填充值左边为使用的列,0标志表示用零来填充
9. 二进制I/O
把数据写到文件效率最高的方法是用二进制形式写入,避免了在数值转换为字符串过程中所涉及的开销和精度损失。
size_t fread( void *buffer, size_t size, size_t count, FILE *stream);
size_t fwrite( void *buffer, size_t size, size_t count, FILE *stream);
buffer:指向用于保存数据的内存位置的指针
size:缓冲区中每个元素的字节数
count:读取或写入的元素数
stream:数据读取或写入的流
返回值为实际读取或写入的元素数目(而非字节)
10. 刷新和定位函数
int fflush( FILE *stream);
迫使输出流的缓冲区内的数据进行物理写入,不管他是不是已经写满。保证调试信息实际打印出来,而不是保存在缓冲区中直到以后才打印。
long ftell( FILE *stream);
int fseek( FILE *stream, long offset, int from);
ftell:返回流的当前位置(距离文件起始位置的偏移量)
- 在二进制文件中,该值就是当前位置距离文件起始位置之间的字节数
- 文本流中,该值表示一个位置,因为行末字符的转换,不一定准确等于字符数,但是ftell函数返回值总是可以用于fseek中,作为一个距离文件起始位置的偏移量
fseek:在一个流中定位
—-from————————–定位到——————–
SEEK_SET —————–从流的起始位置起offset个字节,offset必须是非负值
SEEK_CUR —————-从流的当前位置起offset个字节,offset可正可负
SEEK_END—————-从流的尾部位置起offset个字节,offset可正可负,正:定位到文件尾后面
11. 流错误函数
int feof( FILE *stream);
int ferror( FILE *stream);
void clearerr( FILE *stream);
feof:如果当前位于文件尾,feof返回真
ferror:报告流的错误状态,如果出现任何读写错误函数返回真
clearerr:对指定流的错误标志进行重置
12. 文件操纵函数
int remove(char const *filename); //删除一个指定的文件
int rename(char const *oldname, char const *newname); //改变一个文件的名字