有书共读22《C primer Plus》
1、标准I/O包除了可移植以外还有两个好处。第一,标准I/O有许多专门的函数简化了处理不同I/O的问题。第二,输入和输出都是缓冲的。
2、fopen函数功能打开磁盘内的文件,使程序能对文件进行读写。
函数原型:FILE *fopen(const char *path, const char * mode);
传入参数说明:
*path——所要打开的文件和路径
*mode——打开文件的模式
返回值:文件顺利打开后,指向该流的文件指针就会被返回,若文件打开失败则返回NULL。注意:一般打开文件后会做一些文件读取或写入的动作,若打开文件失败,接下来的读写动作也无法顺利进行,所以fopen()后需要做错误判断及处理。
参数说明:参数path字符串包含欲打开的文件路径及文件名;参数mode字符串则代表着流形态,提供了“r”、“w”、“a”、“+”、“b”、“r”六种模式选择符号,常用的模式如下:
“r” :以只读方式打开文件,该文件必须存在。
“w” :打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
“a” :以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
“r+” :以可读写方式打开文件,该文件必须存在。
“w+” :打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
“a+”:以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留)
“rb” :只读打开一个二进制文件,只允许读数据。
“wb” :只写打开或建立一个二进制文件,只允许写数据。
“ab” :追加打开一个二进制文件,并在文件末尾写数据。
“rb+” :读写打开一个二进制文件,允许读写数据,文件必须存在。
“wb+” :读写打开或建立一个二进制文件,允许读和写。
“ab+” :读写打开一个二进制文件,允许读,或在文件末追加数据。
“rt” :只读打开一个文本文件,只允许读数据。
“wt” :只写打开或建立一个文本文件,只允许写数据。
“at” :追加打开一个文本文件,并在文件末尾写数据。
“rt+” :读写打开一个文本文件,允许读和写。
“wt+” :读写打开或建立一个文本文件,允许读写。
“at+” :读写打开一个文本文件,允许读,或在文件末追加数据。
3、gets函数:从标准输入设备读字符串函数,其可以无限读取,不会判断上限,以回车结束读取,所以程序员应该确保缓冲区的空间足够大,以便在执行读操作时不发生溢出。
功能:从stdio流中读取字符串,直至接受到换行符或EOF时停止,并将读取的结果存放在buffer指针所指向的字符数组中。换行符不作为读取串的内容,读取的换行符被转换为‘\0’空字符,并由此来结束字符串。
返回值:读入成功,返回与参数缓冲区相同的指针;读入过程中遇到EOF(End-of-File)或发生错误,返回NULL指针。所以在遇到返回值为NULL的情况,要用ferror或feof函数检查是发生错误还是遇到EOF。
4、putc函数:功 能:输出字符到指定流中
putc()与fputc()等价。不同之处为:当putc函数被定义为宏时,它可能多次计算stream的值。
关于fputc():
原型:int fputc(int ch,FILE*fp)
功能:在fp所指向的文件的当前读写位置写入一个字符。写入字符成功则函数返回值为该字符的ASCII值,写入字符不成功则返回值为EOF。
向文件写入一个字符后,文件读写位置指针向后移动一个字节。
与putc一样一般用法为“fputc(ch,fp)”,包含在头文件“stdio.h”中
5、exit()函数
所在头文件:stdlib.h(如果是“VC6.0”的话头文件为:windows.h)
功 能: 关闭所有文件,终止正在执行的进程。
exit(0)表示正常退出,
exit(x)(x不为0)都表示异常退出,这个x是返回给操作系统(包括UNIX,Linux,和MS DOS)的,以供其他程序使用。
stdlib.h: void exit(int status);//参 数status,程序退出的返回值
6、fclose函数:功能是关闭一个流。注意:使用fclose()函数就可以把缓冲区内最后剩余的数据输出到内核缓冲区,并释放文件指针和有关的缓冲区。
函数原型:int fclose( FILE *fp );
返回值:如果流成功关闭,fclose 返回 0,否则返回EOF(-1)。(如果流为NULL,而且程序可以继续执行,fclose设定error number给EINVAL,并返回EOF。)
7、fprintf函数:是C/C++中的一个格式化库函数,位于头文件<cstdio>或<bits/stdc++.h>中,其作用是格式化输出到一个流/文件中;
函数原型:int fprintf( FILE *stream, const char *format, [ argument ]...),fprintf()函数根据指定的格式(format)向输出流(stream)写入数据(argument)。
参数说明:FILE*stream:文件指针
const char*format:输出格式
[argument]:附加参数列表
函数说明:fprintf( )会根据参数format 字符串来转换并格式化数据, 然后将结果输出到参数stream 指定的文件中, 直到出现字符串结束('\0')为止。
8、fscanf函数:位于头文件<stdio.h>中,函数原型为int fscanf(FILE*stream, constchar*format, [argument...]); 其功能为根据数据格式(format)从输入流(stream)中写入数据(argument);与fgets的差别在于:fscanf遇到空格和换行时结束,注意空格时也结束,fgets遇到空格不结束。
9、fgets函数:从文件结构体指针stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋'\0'),如果文件中的该行,不足bufsize-1个字符,则读完该行就结束。如若该行(包括最后一个换行符)的字符数超过bufsize-1,则fgets只返回一个不完整的行,但是,缓冲区总是以NULL字符结尾,对fgets的下一次调用会继续读该行。函数成功将返回buf,失败或读到文件结尾返回NULL。因此我们不能直接通过fgets的返回值来判断函数是否是出错而终止的,应该借助feof函数或者ferror函数来判断。
函数原型
char *fgets(char *buf, int bufsize, FILE *stream);
参数
*buf:字符型指针,指向用来存储所得数据的地址。
Bufsize:整型数据,指明存储数据的大小。
*stream:文件结构体指针,将要读取的文件流。
返回值
1. 成功,则返回第一个参数buf;
2. 在读字符时遇到end-of-file,则eof指示器被设置,如果还没读入任何字符就遇到这种情况,则buf保持原来的内容,返回NULL;
3. 如果发生读入错误,error指示器被设置,返回NULL,buf的值可能被改变。
10、fputs函数:具有的功能是向指定的文件写入一个字符串(不自动写入字符串结束标记符‘\0’)。成功写入一个字符串后,文件的位置指针会自动后移,函数返回值为非负整数;否则返回EOF(符号常量,其值为-1)。
函数原型:int fputs(const char *str, FILE *stream);
(1)*str:这是一个数组,包含了要写入的以空字符终止的字符序列。
(2)*stream:指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流
11、rewind函数:C程序中的库函数,功能是将文件内部的指针重新指向一个流的开头。
功能:将文件内部的位置指针重新指向一个流(数据流/文件)的开头
注意:不是文件指针而是文件内部的位置指针,随着对文件的读写文件的位置指针(指向当前读写字节)向后移动。而文件指针是指向整个文件,如果不重新赋值文件指针不会改变。rewind函数作用等同于(void)fseek(stream, 0L, SEEK_SET);
用 法: void rewind(FILE *stream);
12、fseek函数:函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere(偏移起始位置:文件头0(SEEK_SET),当前位置1(SEEK_CUR),文件尾2(SEEK_END))为基准,偏移offset(指针偏移量)个字节的位置。如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。
注意:文件指针指向文件/流。位置指针指向文件内部的字节位置,随着文件的读取会移动,文件指针如果不重新赋值将不会改变或指向别的文件。
函数原型:int fseek(FILE *stream, long offset, int fromwhere);
返回值:成功,返回0,失败返回-1,并设置error的值,可以用perror()函数输出错误。
fseek position the file(文件) position(位置) pointer(指针) for the file referenced by stream to the byte location calculated by offset.
13、ftell函数:用于得到文件位置指针当前位置相对于文件首的偏移字节数。在随机方式存取文件时,由于文件位置频繁的前后移动,程序不容易确定文件的当前位置。该函数对大于231-1文件,即:2.1G以上的文件操作时可能出错。
13、fflush函数:功能是冲洗流中的信息,该函数通常用于处理磁盘文件。fflush()会强迫将缓冲区内的数据写回参数stream 指定的文件中。
14、fgetpos函数:
函数原型: int fgetpos(FILE * restrict stream,fpos_t * restrict pos);
函数功能:在pos所指的位置放置一个fpos_t值,这个值描述了文件中的一个位置。
返回值:如果成功,函数返回0;否则返回一个非零值。
15、fsetpos函数:将文件指针定位在pos指定的位置上。该函数的功能与前面提到的fgetpos相反,是将文件指针fp按照pos指定的位置在文件中定位。pos值以内部格式存储,仅由fgetpos和fsetpos使用。
16、feof函数:功能是检测流上的文件结束符,如果文件结束,则返回非0值,否则返回0(即,文件结束:返回非0值,文件未结束,返回0值),文件结束符只能被clearerr()清除。
17、ferror,函数名,在调用各种输入输出函数(如 putc.getc.fread.fwrite等)时,如果出现错误,除了函数返回值有所反映外,还可以用ferror函数检查。 它的一般调用形式为 ferror(fp);如果ferror返回值为0(假),表示未出错。如果返回一个非零值,表示出错。应该注意,对同一个文件 每一次调用输入输出函数,均产生一个新的ferror函 数值,因此,应当在调用一个输入输出函数后立即检 查ferror函数的值,否则信息会丢失。在执行fopen函数时,ferror函数的初始值自动置为0。
18、ungetc()函数:用于将一个字符退回到输入流中,这个退回的字符会由下一个读取文件流的函数取得。
原型:int ungetc(char c, FILE *stream);
参数:c为要退回的字符,stream为要退回的输入流。
返回值:若该函数执行成功,返回非零值;否则,返回0。
19、setvbuf()函数:用来设定文件流的缓冲区。
原型:int setvbuf(FILE * stream, char * buf, int type, unsigned size);
stream为文件流指针,buf为缓冲区首地址,type为缓冲区类型,size为缓冲区内字节的数量。
参数说明:IOFBF (满缓冲):当缓冲区为空时,从流读入数据。或当缓冲区满时,向流写入数据。_IOLBF (行缓冲):每次从流中读入一行数据或向流中写入—行数据。_IONBF (无缓冲):直接从流中读入数据或直接向流中写入数据,而没有缓冲区
返回值:成功返回0,失败返回非0。
20、fread是一个函数,它从文件流中读数据,最多读取count个项,每个项size个字节,如果调用成功返回实际读取到的项个数(小于或等于count),如果不成功或读到文件末尾返回 0。
函数原型:size_t fread ( void *buffer, size_t size, size_t count, FILE *stream) ;
参数:buffer用于接收数据的内存地址
size要读的每个数据项的字节数,单位是字节
count要读count个数据项,每个数据项size个字节.
stream输入流
21、write()函数: 是 C 语言标准库中的一个文件处理函数,功能是向指定的文件中写入若干数据块,如成功执行则返回实际写入的数据块数目。该函数以二进制形式对文件进行操作,不局限于文本文件。
用法:size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);
返回值:返回实际写入的数据块数目
(1)buffer:是一个指针,对fwrite来说,是要获取数据的地址;
(2)size:要写入内容的单字节数;
(3)count:要进行写入size字节的数据项的个数;
(4)stream:目标文件指针;
(5)返回实际写入的数据项个数count。
说明:写入到文件的哪里?这个与文件的打开模式有关,如果是w+,则是从file pointer指向的地址开始写,替换掉之后的内容,文件的长度可以不变,stream的位置移动count个数;如果是a+,则从文件的末尾开始添加,文件长度加大。
fseek对此函数有作用,但是fwrite函数写到用户空间缓冲区,并未同步到文件中,所以修改后要将内存与文件同步可以用fflush(FILE *fp)函数同步。
22、ANSIC提供两种文件打开模式:二进制和文本。以二进制模式打开文件时,可以逐字节读取文件;以文本模式打开文件时,会把文件内容从文本的系统表示法映射为C表示法。对于系统UNIX和Linux系统,这两种模式完全相同。
通常,输入函数getc()、fgets()、fscanf()和fread()都从文件开始出按顺序读取文件。然而,fseek()和ftell()函数让程序可以随机访问文件中的任意位置。Fgetpos()和fsetpos()把类似的功能扩展至更大的文件。与文本模式相比,二进制模式更容易进行随机访问。
23、编程练习:
13-7a:
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int ch1, ch2; FILE * f1; FILE * f2; if (argc != 3) { printf("Usage: %s file1 file2\n", argv[0]); exit(EXIT_FAILURE); } if ((f1 = fopen(argv[1], "r")) == NULL) { printf("Could not open file %s for input\n", argv[1]); exit(EXIT_FAILURE); } if ((f2 = fopen(argv[2], "r")) == NULL) { printf("Could not open file %s for input\n", argv[2]); exit(EXIT_FAILURE); } ch1 = getc(f1); ch2 = getc(f2); while (ch1 != EOF || ch2 != EOF) { while (ch1 != EOF && ch1 != '\n') { putchar(ch1); ch1 = getc(f1); } if (ch1 != EOF) { putchar('\n'); ch1 = getc(f1); } while (ch2 != EOF && ch2 != '\n') { putchar(ch2); ch2 = getc(f2); } if (ch2 != EOF) { putchar('\n'); ch2 = getc(f2); } } if (fclose(f1) != 0) printf("Could not close file %s\n", argv[1]); if (fclose(f2) != 0) printf("Could not close file %s\n", argv[2]); return 0; } 13-7b: #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int ch1, ch2; FILE * f1; FILE * f2; if (argc != 3) { printf("Usage: %s file1 file2\n", argv[0]); exit(EXIT_FAILURE); } if ((f1 = fopen(argv[1], "r")) == NULL) { printf("Could not open file %s for input\n", argv[1]); exit(EXIT_FAILURE); } if ((f2 = fopen(argv[2], "r")) == NULL) { printf("Could not open file %s for input\n", argv[2]); exit(EXIT_FAILURE); } ch1 = getc(f1); ch2 = getc(f2); while (ch1 != EOF || ch2 != EOF) { while (ch1 != EOF && ch1 != '\n') /* skipped after EOF reached */ { putchar(ch1); ch1 = getc(f1); } if (ch1 != EOF) { if (ch2 == EOF) putchar('\n'); else putchar(' '); ch1 = getc(f1); } while (ch2 != EOF && ch2 != '\n') /* skipped after EOF reached */ { putchar(ch2); ch2 = getc(f2); } if (ch2 != EOF) { putchar('\n'); ch2 = getc(f2); } } if (fclose(f1) != 0) printf("Could not close file %s\n", argv[1]); if (fclose(f2) != 0) printf("Could not close file %s\n", argv[2]); return 0; }
13-12:
#include <stdio.h> #include <stdlib.h> #define ROWS 20 #define COLS 30 #define LEVELS 10 const char trans[LEVELS + 1] = " .':~*=&%@"; void MakePic(int data[][COLS], char pic[][COLS], int rows); void init(char arr[][COLS], char ch); int main() { int row, col; int picIn[ROWS][COLS]; char picOut[ROWS][COLS]; char fileName[81]; FILE * infile; init(picOut, 'S'); printf("Enter name of file: "); scanf("%80s", fileName); if ((infile = fopen(fileName, "r")) == NULL) { fprintf(stderr, "Could not open data file.\n"); exit(EXIT_FAILURE); } for (row = 0; row < ROWS; row++) for (col = 0; col < COLS; col++) fscanf(infile, "%d", &picIn[row][col]); if (ferror(infile)) { fprintf(stderr, "Error getting data from file.\n"); exit(EXIT_FAILURE); } MakePic(picIn, picOut, ROWS); for (row = 0; row < ROWS; row++) { for (col = 0; col < COLS; col++) putchar(picOut[row][col]); putchar('\n'); } return 0; } void init(char arr[][COLS], char ch) { int r, c; for (r = 0; r < ROWS; r++) for (c = 0; c < COLS; c++) arr[r][c] = ch; } void MakePic(int data[][COLS], char pic[][COLS], int rows) { int row, col; for (row = 0; row < rows; row++) for (col = 0; col < COLS; col++) pic[row][col] = trans[data[row][col]]; }