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;
}
3) 读取二进制文件
这时候就不能使用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");
2--读写一个结构,则代码如下:
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;
}
程序输出: