1. 缓冲区
标准I/O提供了三种类型的缓冲:
1) 全缓冲:在填满标准I/O缓冲区后才进行实际I/O操作。
2) 行缓冲:输入和输出遇到换行符的时候,标准I/O执行I/O操作。
3) 不带缓冲
通常,系统默认的是:
1) 标准出错是不带缓冲的
2) 如若是涉及终端设备的其他流,则它们是行缓冲的;否则是全缓冲的。
#include <stdio.h> void pr_stdio( const char *, FILE * ); int main( void ) { FILE *fp; fputs("enter any character\n", stdout ); if ( getchar() == EOF ) printf("getchar error\n"); fputs("one line to standard error\n", stderr ); pr_stdio("stdin",stdin); pr_stdio("stdout",stdout); pr_stdio("stderr",stderr); if ( ( fp = fopen("/etc/xml", "r")) == NULL) printf("fopen error\n"); pr_stdio("/etc/xml", fp); return 0; } void pr_stdio( const char *name, FILE *fp ) { printf("stream=%s,", name); if ( fp->_IO_file_flags & _IO_UNBUFFERED) printf("unbuffered"); else if ( fp->_IO_file_flags & _IO_LINE_BUF ) printf("line buffered"); else printf("fully buffered"); printf(",buffer size=%d\n", fp->_IO_buf_end - fp->_IO_buf_base ); }
备注:注意缓冲由“行缓冲”变为“全缓冲”。
2. 读和写流
1) 每次一个字符的读写流
#include <stdio.h> int main( void ) { int c; FILE *fp1 = fopen("temp", "r" ); FILE *fp2 = fopen("temp.foo", "w "); if ( NULL == fp1 || NULL == fp2 ){ printf("fopen error\n"); return 1; } while ( ( c = getc( fp1 ) ) != EOF ){ if ( putc( c, fp2 ) == EOF ){ printf("write file error\n"); } } if ( ferror( fp1 ) ){ printf("input error\n"); clearerr( fp1 ); } return 0; }程序输出:
2) 每次一行字符读写流
#include <stdio.h> int main( void ) { char buf[ 10 ]; FILE *fd1 = fopen("temp", "r"); FILE *fd2 = fopen("temp.foo","w"); if ( NULL == fd1 || NULL == fd2 ){ printf("open file error\n"); return 1; } while ( fgets( buf, 10, fd1 ) != NULL ){ if ( fputs( buf, fd2 ) == EOF ){ printf("write error\n"); return 1; } } return 0; }
这时候就不能使用getc/putc,fgets/fputs。我们通常需要一次读写整个结构。
size_t fread( void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp ); size_t fwrite( const void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp );1--读写一个二进制数组。例如,为了将一个浮点数组的第2~5个元素写至一个文件上,则代码如下:
float data[ 10 ]; if (fwrite(&data[2], sizeof(float), 4, fp ) != 4 ) printf("write error\n");
struct { short count; long total; char name[ NAMESIZE ]; } item; if ( fwrite(&item, sizeof(item), 1, fp ) != 1 ) printf("write error\n");
#include <stdio.h> struct people{ char *name; int age; }; int main( void ) { int c; char buf[ 10 ]; FILE *fp1 = fopen("people", "w+"); FILE *fp2 = fopen("people.foo","w+"); if ( NULL == fp1 || NULL == fp2 ){ printf("open file error\n"); return 1; } struct people p1; struct people p2; struct people p3; struct people p4; p1.name = "小雷"; p1.age = 25; p2.name = "小猫咪"; p2.age = 24; if ( fwrite(&p1, sizeof( p1 ), 1, fp1 ) != 1 ){ printf("write error\n"); return 1; } if ( fwrite( &p2, sizeof( p2 ), 1, fp1 ) != 1 ){ printf("write error\n"); return 1; } if ( fseek( fp1, 0, SEEK_SET ) != 0 ){ printf("fseek error\n"); return 1; } while ( ( c = getc( fp1 ) ) != EOF ){ if ( putc( c, fp2 ) == EOF ){ printf("write error\n"); return 1; } } // while ( fgetc( buf, 10, fp1 ) != NULL ){ // if ( fputs( buf, fp2 ) == EOF ){ // printf("write file error\n"); // return 1; // } // } if ( fseek( fp2, 0, SEEK_SET ) != 0 ){ printf("fseek error\n"); return 1; } if ( fread( &p3, sizeof( p3 ), 1, fp2 ) != 1 ){ printf("read error\n"); return 1; } if ( fread( &p4, sizeof( p4 ), 1, fp2 ) != 1 ){ printf("read error\n"); return 1; } printf("name is:%s, age is:%d\n", p3.name, p3.age ); printf("name is:%s, age is:%d\n", p4.name, p4.age ); return 0; }
备注:不能使用fgets/fputs函数。因为二进制文件并没有"行"的概念。
3. 临时文件
#include <stdio.h> #define MAXLINE 4096 int main( void ) { char name[L_tmpnam], line[MAXLINE]; FILE *fp; printf("%s\n", tmpnam(NULL)); tmpnam(name); printf("%s\n", name); if ( ( fp = tmpfile()) == NULL ){ printf("tmpfile error\n"); return 1; } fputs("one line of output\n", fp ); rewind(fp); if ( fgets(line,sizeof(line), fp) == NULL ){ printf("fgets error\n"); return 1; } fputs(line, stdout); return 0; }