天天看点

文件I/O流

对于每一个ANSI C程序而言,至少打开三个流:标准输入(stdin)、标准输出(stdout)、标准错误(stderr),他们都是一个指向FILE结构的指针。

标准输入为:键盘设备 

标准输出为:终端或屏幕。

标准库I/O一般情况:

1. 程序必须为同时处于活动状态的每个文件声明一个指针变量,其类型为: FILE* ,这个指针指向一个结构,当它处于活动状态时由流使用。

2. 流通过fopen函数打开,打开流的时候,必须指定需要访问的文件或者设备已经访问的方式。fopen函数和操作系统去验证文件或者设备确实存在,验证访问方式,然后初始化FILE结构

3.根据需要对文件进行读取和写入。

4.最后,fclose函数可以关闭流。关闭一个流可以防止与它相关的文件被再次访问,保证任何存储于缓冲区中的数据被正确的写入文件中。

文件I/O流

1.FILE * fopen ( const char * filename, const char * mode ); 

1> r 只读 ,文件必须已存在

2> w 只写,如果文件不存在则创建,如果文件已存在则把文件长度截断(Truncate)为0字节再重新写,也就是替换掉原来的文件内容

3> a 只能在文件末尾追加数据,如果文件不存在则创建

4> r+ 允许读和写,文件必须已存在

5> w+ 允许读和写,如果文件不存在则创建,如果文件已存在则把文件长度截断为0字节再重新写

6> a+ 允许读和追加数据,如果文件不存在则创建

使用fopen打开文件时如果出错,fopen将返回NULL并设置errno,必须对此进行处理:

if (fp == NULL) {
         perror("fopen");
         exit(1);
}
           

2.int fclose ( FILE * stream );//需与fopen配套使用(打开流一定要关闭)

字符I/O:

3.int getc ( FILE * stream ); 

4.int putc ( int character, FILE * stream );

int main()
{
	FILE *fp = fopen("log.txt", "wt");
	if (NULL == fp)
	{
		perror("fopen");
		return 1;
	}
	//int i = 0;                                //将hello czf!写入log.txt
	//while (i++ < 10)
	//{
	//	fputs("hello czf!\n", fp);
	//} 

	//int ch;                                   //计算文件中的!
	//size_t count = 0;
	//do{
	//	ch = getc(fp);
	//	if ('!' == ch)
	//	{
	//		printf("%c : %d\n",ch, count);
	//	}
	//	count++;
	//} while (ch != EOF);
	//printf("end = %d\n", ch);

	int ch = 'A';

	while (ch <= 'Z')                              //将A-Z逐个写入fp
	{
		putc(ch, fp);
		putc('\n', fp);
		ch++;
	}

	fclose(fp);
	return 0;
}
           

未格式化的行I/O

char * gets ( char * str ); 

int puts ( const char * str )

5.char * fgets ( char * str, int num, FILE * stream ); 

6.int fputs ( const char * str, FILE * stream ); 

int main()
{
	char buf[255] = {0};
	while (1)                                    //从标准输入读入,打印到标准输出
	{
		gets(buf);
		if (strcmp("quit", buf) == 0)
		{
			break;
		}
		//printf("echo:%s\n", buf);
		puts(buf);
	}
	printf("quit!\n");

	FILE *fp = fopen("myfile.txt", "w");
	if (NULL == fp)
	{
		perror("fopen");
		return 1;
	}
	char buf[128];
	while (1)                                     //从文件读到缓冲区,再从缓冲区读到屏幕
	{
		fgets(buf, 10, fp);
		if (feof(fp))
		{
			printf("end of file!   quit!\n");
			break;
		}
		fputs(buf, stdout);		
		fflush(stdout);
		Sleep(1000);
	}

	char buf[128];
	while (1)
	{
		printf("enter:");
		fgets(buf, 128, stdin);
		if (strncmp("quit", buf, 4) == 0)
		{
			break;
		}
		fputs(buf, fp);
	}

	fclose(fp);
	return 0;
}
           

格式化的行I/O

int scanf ( const char * format, ... ); //返回成功转换和分配的字段的数量

int printf ( const char * format, ... ); //返回值为打印的字符数,出现错误,打印负值 printf("%d", printf("%d",2));  21

输出缓存刷新到目标地址的时机:

1.\n

2.scanf

3.exit

4.内核缓存满

5.fflush(stdout);

7.int fscanf ( FILE * stream, const char * format, ... ); 

8.int fprintf ( FILE * stream, const char * format, ... ); 

#include <stdio.h>
#include <string.h>
int main()
{
	float f;
	char buf[16] = {0};
	char name[16] = {0};
	FILE *fp = fopen("log.txt", "w+");
	if(NULL == fp)
	{
		perror("fopen");
		return 1;
	}
	
	fprintf(fp, "%f %s", 3.14159, "PI");		
	rewind(fp);                                     //将流的读写位置充值到最开始

	fscanf(fp, "%f %s", &f, buf);

	printf("%f, %s\n", f, buf);

	fclose(fp);
	return 0;
}

           

二进制I/O:

9.size_t fread ( void * ptr, size_t size, size_t count, FILE* stream );  <缓冲区名> <一个单元的大小> <要读多少单元> <流>

10.size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );  <写出缓冲区> <单元大小> <多少个单元> <流>

#include <stdio.h>

int main()
{
	char buff[] = {'A' , 'B' , 'C'};
	FILE *fp = fopen("myfile.bin","wb+");
	if(NULL == fp){
		perror("fopen");
		return 1;
	}	

	fwrite(buff,sizeof(char),sizeof(buff),fp);
	
	fclose(fp);
	return 0;
}
           

11.int fseek(FILE *stream, long offset, int whence); <流> <偏移量> <偏移位置>//进行文件写入位置的定位

fseek的whence和offset参数共同决定了读写位置移动到何处,whence参数的含义如下:

SEEK_SET

从文件开头移动offset个字节

SEEK_CUR

从当前位置移动offset个字节

SEEK_END

从文件末尾移动offset个字节

offset可正可负,负值表示向前(向文件开头的方向)移动,正值表示向后(向文件末尾的方向)移动,如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸,从原来的文件末尾到fseek移动之后的读写位置之间的字节都是0。

12. void rewind(FILE *stream)  ==   int fseek(FILE *stream, 0, SEEK_SET) //回到流的最开始

13.long ftell(FILE *stream);//报告每次写入的位置

14.int fflush(FILE *stream);

15.对比EOF和feof函数的区别?

feof()判断文件结尾:  二级制文本的结束标志

EOF   文本文件的结尾标志

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int main()

{
	char buf[20];
	FILE *fp = fopen("/bin/ls","rb");
	if(NULL == fp)
	{
		perror("fopen");
		return 1;
	}

	fseek(fp,0,SEEK_END);                   //将写入位置移动到文件结尾
	long lsize = ftell(fp);                 //报告文件为准
	rewind(fp);                             //把光标移动到文件开始

	printf("size -> %d\n",lsize);
	
	char *buff = (char*)malloc(sizeof(char)*lsize);
	assert(buff);	
	ssize_t t = fread(buff,lsize, 1 ,fp);   //将fp读进buff
	
	FILE *ofp = fopen("myls","wb+");
	if(NULL == ofp){
		perror("fopen");
		return 1;
	}
	
	fwrite(buff,lsize, 1, ofp);

	fclose(fp);
	fclose(ofp);
	free(buff);
//	float d;
//	char name[20];
//	FILE *fp = fopen("czf.txt","w+");
//	if(NULL == fp)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	int i = 0;
//	for(; i < 5; i++){
//		printf("Please Enter a name:\n");
//		gets(name);
//		fprintf(fp, "Name %d is [%-10.20s]\n",i+1 ,name );
//	}
	
//	fprintf(fp, "%s %f\n","PI" ,3.14 );
//	rewind(fp);
//	fscanf(fp,"%s %f",&buff, &d);
//	printf("%s %f\n",buff,d);	

//	fclose(fp);
	return 0;
}