天天看點

檔案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;
}