C和指针 第十五章 文件I/O
stdio.h中包含了声明FILE结构
struct _iobuf { char *_ptr; //文件输入的下一个位置 int _cnt; //当前缓冲区的相对位置 char *_base; //指基础位置(应该是文件的其始位置) int _flag; //文件标志 int _file; //文件的有效性验证 int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取 int _bufsiz; //文件的大小 char *_tmpfname; //临时文件名 };
FILE作为一种结构,用于访问一个流,如果激活了好几个流,那么每个流都有一个对应的FILE与他关联。当需要对流执行一些操作,调用一些函数,并向他们提供一个相关联的FILE参数。
对于ansi c运行时至少有三个流,标准输入stdin,标准输出stdout,标准错误stderr,他们都是指向FILE结构的指针。标准输入一般是键盘设备,输出是屏幕终端,一般错误和输出都是相同的,也可通过系统的输入\输出重定向进行指定输入输出。
$: program < source > output
从source输入,输出到output。
流I/O总览
通过fopen函数打开一个流,指定读写模式,如果成功打开返回一个FILE *,打开失败返回NULL。
FILE *fopen(char *const *name, char const *mode);
下面是fopen的常用模式
读取 | 写入 | 添加 | |
文本 | r | w | a |
二进制 | rb | wb | ab |
如果模式是a+,那么表示打开文件更新,可读可写。
fclose关闭流,关闭流可以防止文件被再次访问,保证储存于缓冲区的数据被正确的写入到文件。释放的FILE结构体,可以用于其他另外的文件。
int fclose(FILE *f);
执行成功返回0,否则返回EOF。
文本IO:
文本I/O函数包括三种基本的形式处理数据:单个字符,字符串,格式输入输出
1.字符IO:
fgetc和fputc是真正的函数,其他的都是通过#define指令定义的宏
int getchar() /*说明:从stdin读取1个字符 返回值:成功,返回该字符;出错,返回EOF;*/ int fgetc(FILE fp) /*说明:功能同getchar,默认从文件fp读取; 返回值:成功,返回该字符;出错,返回EOF; 可以重定向 */ int getc(FILE fp) /*说明:功能与fgetc相同,但getc既可以被用作 函数实现,也可以被用作宏实现,并且它的编码效率 可能会更高. 可以重定向 */ int putchar(int ch) /*说明:向stdout输出字符ch; 返回值:成功,返回该字符;出错,返回EOF*/ int fputc(int c, FILE fp) /*说明:功能同putchar,默认向fp输出字符ch; 返回值:成功,返回该字符;出错,返回EOF */ int putc(int c , FILE fp) /*说明:功能与fputc相同,但putc与getc一样既可能被用作 函数实现,也可能被用作宏实现,并且它的编码效率可能会更高; 可以重定向 */
下面的代码用于从命令行中读取输入,写入到文本中
#includeint main() { char input; //D盘新建文件写入命令行输入 FILE *file = fopen("D:/c.txt", "w"); //读取输入 while ((input = getchar()) != EOF) { //输入q结束 if (input != 'q') { //打印输入字符,putc和fputc储存输入字符 putchar(input); fputc(input, file); putc(input, file); }else{ fclose(file); break; } } return 0; }
执行:
打开文件D:/c.txt,每个字符被fputc和putc输出两遍
撤销字符IO
int ungetc(int character, FILE *stream);
把先前读入的字符返回到流中,这样可以重新被读取。下面的代码读入字母,遇到数字重新换行读取:
#include#include int main() { int input; while((input = getchar()) != EOF && !isdigit(input)){ putchar(input); } //将数字放回标准输入 ungetc(input, stdin); puts("\n\ndigit:"); while((input = getchar()) != EOF && isdigit(input)){ putchar(input); } return 0; }
2.文本行(字符串) I/O
char gets(char str) /*说明:从stdin读取字符串(不包括'n')写入到字符串str中; 返回值:成功,返回str首地址;错误,返回NULL*/ char fgets(char str, int N, FILE fp) /*说明:默认从文件fp中读取N个字符(包括'n')写入到字符串str中, 如果实际输入字符串小于N, fgets自动添加'n', 返回值:成功,返回字符串首地址;错误或遇到EOF,返回NULL; 可以重定向 */ int puts(const char str) /*说明:向stdout输出字符串str,然受输出一个'n', 返回值:成功,返回非负值;错误,EOF*/ int fputs(const char str, FILE fp) /*说明:功能同puts,默认向文件fp写入字符串str; 返回值:成功,返回非负值;错误,EOF; 可以重定向 */
下面的代码用于,从标准输入读取字符串到buffer中,注意buffer的大小可能导致溢出,因为gets没有限定读入的长度。
#include#include #define BUFFER_SIZE 100 int main() { char buffer[BUFFER_SIZE]; //D盘新建文件写入命令行输入 FILE *file = fopen("D:/c.txt", "w"); //读取输入,注意gets读取输入对长度没有限制,可能会造成溢出 while (gets(buffer) != NULL) { //只输入一个q结束 if (strlen(buffer) == 1 && buffer[0] == 'q') { fclose(file); puts("Bye Bye"); break; }else{ //将输入字符串打印,然后写入文件中 puts(buffer); fputs(buffer, file); } } puts("------------------------------------------------"); file = fopen("D:/c.txt", "r"); //从文件中每次读取5个字符到buffer中,然后打印 while (fgets(buffer, 10, file) != NULL) { puts(buffer); } while (1) ; return 0; }
运行:
3.格式化I/O
当格式化字符串到达末尾或者读取的输入不在匹配格式字符串所指定的类型是,输入就停止,在任何情况下,被转换的输入值的数目作为函数的返回值返回,如果在任何输入值被转换之前就到达末尾,函数就返回常量EOF。
int scanf(const char format, ...) /*说明:根据format从stdin格式化读取N个值,并输入到... 返回值:成功,返回读取的项数;出错,返回EOF */ int fscanf(FILE fp, const char format, ...) /*说明:功能同scanf,默认从文件fp读取, 返回值:成功,返回读取的项数;出错或遇到文件尾,返回EOF */ 可以重定向 */ /*int sscanf(const char buf, const char format, ...) 说明:根据format从buf格式化读取N个值,并输入到... 返回值:成功,返回读取的项数;出错,返回EOF */ int printf(const char format, ...) /*说明:根据format格式化数据,并输出到stdout 返回值 成功,返回输出字符数;错误,返回负数; */ int fprintf(FILE fp, const char format, ...) /*说明:功能同printf,默认向文件fp写入; 可以重定向 */ int sprintf(char buf, const char format, ...) /*说明:根据format格式化数据,并输出到buf, 返回值:成功,返回输出字符数;错误,返回负数 */
下面的代码从文件中格式化读入,然后提取内容,格式化写入到字符串和文本中
#include#define BUFFER_SIZE 100 int main() { char string[100]; char tmp[100]; int num; //D盘打开文件 FILE *readFile = fopen("D:/read.txt", "r"); FILE *writeFile = fopen("D:/write.txt", "w"); //格式化读入文件内容 while (fscanf(readFile, "%3d,,,%s", &num, &string) != EOF) { //格式化写入字符串tmp中 sprintf(tmp, "id: %d type: %-10s\n", num, string); printf("%s\n", tmp); //格式化写入文件中 fprintf(writeFile, "id: %-4d type: %s\n", num, string); } return 0; }
read.txt文件内容:
255,,,棉衣 255,,,毛呢大衣 255,,,风衣 255,,,打底衫 255,,,情侣装 255,,,毛呢短裤 255,,,牛仔裤 255,,,加绒打底裤 255,,,小脚裤 255,,,半身裙 255,,,毛呢连衣裙 255,,,长袖连衣裙
运行:
write.txt文件内容:
id: 255 type: 棉衣 id: 255 type: 毛呢大衣 id: 255 type: 风衣 id: 255 type: 打底衫 id: 255 type: 情侣装 id: 255 type: 毛呢短裤 id: 255 type: 牛仔裤 id: 255 type: 加绒打底裤 id: 255 type: 小脚裤 id: 255 type: 半身裙 id: 255 type: 毛呢连衣裙 id: 255 type: 长袖连衣裙