C 文件处理

文件分类:操作中用到的二进制和ASCII方式。

二进制文件

形式:把内存中的数据按其在内存中的存储形式原样输出到磁盘上存放。

优点:可以节省外存空间和转换时间。
缺点:一个字节并不对应一个字符,不能直接输出字符形式。

一般中间结果数据需要暂时保存在外存上,以后又需要输入内存的,常用二进制文件保存。

微软\textup{}ASCII文件形式:

每一个字节放一个ASCII代码。
优点:便于对字符进行逐个处理,也便于输出字符。
缺点:一般占存储空间较多,而且要花费转换时间。

 

C语言文件指针定义

文件的读写(头文件均为stdio.h)

fopen函数

头文件:stdio.h

功    能:以type方式打开filename文件并返回该文件的指针

用    法:FILE *fopen(char *filename,char *type);    

返回值:filename的文件指针;如果打开失败fopen 函数返回一个NULL 指针;

特点就是单个字母的是 "文件文本" 的操作,双字母的是二进制的”文件操作“。

常用的文件操作是 "r" "w" "a",追加最是常用。

fclose函数

头文件:stdio.h

功   能:关闭一个流

用   法:int fclose(FILE *stream);

返回值:成功返回0,不成功返回EOF(-1)

字符读写函数

fgetc函数

功   能:从fp所指向的文件中读取字符
用   法:int fgetc(FILE *fp);
返回值:返回文件fp所指向的文件中的字符值(EOF为文件尾)
补   充:
1.调用该函数时,文件使用方式必须是以读或读写方式打开的。
2.在文件内部有一个位置指针,用来指向文件的当前读写

fputc函数

功能:将字符(ch的值)输出到fp所指向的文件中去。

用法:int futc(int ch,FILE *fp);

返回值:写入成功返回写入字符ch

             不成功返回EOF

int main()
{
	FILE *fp = fopen("text.txt", "a+");
	if (NULL != fp)
	{
		char str[] = "this text is success !";
		int len = strlen(str);
		int i = 0;
		while (len--)
		{
			fputc(str[i] , fp);
			i++;
		}
		fputc(EOF, fp);
		fseek(fp ,0L ,SEEK_SET);
		char ch = fgetc(fp);
		while (ch != EOF)
		{
			printf("%c", ch);
			ch = fgetc(fp);
		}
	}
	return 0;
}	

字符串读写函数

fgets函数

功   能:从fp所指向的文件(stdin特殊文件)中读取长度为n的字符串保存到string中
用   法:char *fgets(char *str, int n, FILE *fp);
返回值:成功,返回str

           1. 当n<=0 时返回NULL,即空指针。

          2. 当n=1 时,返回空串"".

          3. 如果读入成功,则返回缓冲区的地址。

          4. 如果读入错误或遇到文件结尾(EOF),则返回NULL.

char *fgets(char *str, int n,  FILE *stream)  
   {  
     register int c;  
     register char *cstr;  
     cstr=str;  
     while(--n>0 &&(c = getc(stream))!=EOF)  
     if ((*cstr++=  c) =='\n')  
           break;  
     *cstr ='\0';  
     return (c == EOF && cstr == s) ?NULL :str ;  
    }  
  //可以看出读的是n-1的数据流;

 fgets(...)读入文本行时的两种情况。

          1.如果n大于一行的字符串长度,那么当读到字符串末尾的换行符时,fgets(..)会返回。并且在s的最后插入字符串结束标志'\0'。 而s缓冲区剩余的位置不会再填充。

           example:

              123abc

              fgets(s,10,fp);

              此时,读入七个字符,123abc\n,实际上还有最后的'\0',所以,strlen(s)=7; 如果要去除末尾的\n,s[strlen(s)-1]='\0';便可。

          2.如果n小于等于一行的字符串的长度,那么读入n-1个字符,此时并没有读入\n因为并没有到行尾 ,同样在最后会插入'\0'.

          example:

            123abc

            char  s[5];

            fgets(s,5,fp);

            这时读入4个字符,123a,并没有换行符,所以strlen(s)=4.

注意:

fgets( ) 读入n-1个字符串,后加上 ‘ \n ’ 和 ‘ \0 ’ 字符,所以它的实际字符长度是 n ,最后一位是 ‘ \n ’

int main()
{
	char str1[200];
	fgets(str1, 200, stdin);
	char *pStr = str1;
	int a = strlen(pStr);
	//for (pStr; *pStr != '\n';pStr++);
	while (*pStr++ != '\n');
	printf("%d ,%s\n", a , pStr-2);
	return 0;
}

输入1+‘ \n ’ 查看;存在回车

fputs函数

功   能:将字符串string写入fp所指向的文件中。
用   法:int fputs(char *string, FILE *fp);
返回值:输入成功,返回值0
             输入失败,返回EOF

数据块读写函数


fread函数

功   能:从fp指向的文件中读取n个size大小的数据写入ptr指向的地方
用   法:int fread(void *ptr, int size, int n, FILE *fp);
返回值:成功,返回读取元素个数 也就是 n,所以它的二三参数注意位置
             不成功,返回的是一个小于n 的数所以,要注意条件的判断。

参数说明:
ptr:读入数据的存放地址(首地址)
size:要读写的字节数
n:要进行读写多少个size字节的数据项

1.在使用fread函数的时候,最好使用下面的形式:fread(buf, sizeof(char), sizeof(buf), p);

单个字节读取,每次读取缓冲区的长度,这样就不会出现有些字节被舍弃的情况了。

2.fread可以读二进制文件,有时用字符方式去读文件不能读完整个文件,但是二进制方式就可以 。

这就是因为字符方式用特定的标记结尾的,读取时只要碰到该标记就自动结束。

这就要求用fread() 函数文件打开方式是 "rb" "rb+"这中双字母的读/写方式,例如:open("text.txt" , "rb")

3.在这里, 再次强调一遍: fread, read, recv, fwrite, write, send这类函数针对的是字符(无边界), 而不是字符串(以'\0'作为边界), 与'\0'没有半毛钱的关系。

4.注意到的问题是fread函数不能区分文件是否结尾和出错两种情况。所以必须使用ferror()和feof()函数来确定到底是哪种情况,

fwrite函数

功   能: 从ptr指向的地方读取n个size大小的数据写入fp指向的文件中
用   法:int fwrite(void *ptr, int size, int n, FILE *fp);
返回值:返回写入文件的实际个数

参数说明:ptr:输出数据的地址(首地址)其余同上
注意:这个函数以二进制形式对文件进行操作,不局限于文本文件(最好是二进制 的

下面是例子:

//我们定义一个结构体,fread() 和 fwrite()多数用与结构体的操作
#define SIZE 5
typedef struct
{
	char name[20];
	char num[15];
	char age;
}student;
//向file_name 的文件中写入,以
bool fwrite()
{
	FILE *fp;
	int i;
	char file_name[50];

	printf("Please input your filename:");
	scanf("%s", file_name);
	if (!(fp = fopen(file_name, "w+")))
	{
		printf("Can not open %s\n", file_name);
		return false;
	}
	for (i = 0; i < SIZE; i++)
	{
		if (fwrite(&stu[i], sizeof(student), 1, fp) != 1)
		{
			printf("D'ont write file!\n");
		}
	}
	fclose(fp);
	return true;
}
//读文件函数
bool fread()
{
	FILE *fp;
	int i;
	char file_name[50];

	printf("Please input the filename you want read:");
	scanf("%s", file_name);
	if (!(fp = fopen(file_name, "rb")))
	{
		printf("Can not open %s\n", file_name);
		return false;
	}
	fseek(fp ,0L , SEEK_SET);
	//位置偏移
	for (i = 0; i < SIZE; i++)
	{
		//返回的是count = 1
		if (int a = fread(&buf[i], sizeof(student), 1, fp) != 1)
		{
			 printf("文件读取失败!%d\n",a);
			 return false;
		}		
	}	
	fclose(fp);
	printf("%s\n", "读取结束");
	for (i = 0; i < SIZE; i++)
	{
		printf("name:%s num:%s age:%c\n", buf[i].name, buf[i].num, buf[i].age);
	}
	return true;
}
//定义文件缓冲区buf[SIZE]
student stu[SIZE], buf[SIZE];;
//声明函数
bool fwrite();
bool fread();
void freadS(int size);

int main()
{
	int i;
	printf("%d\n", sizeof(student));
	//freadS(sizeof(student));
	if (!fread())
	{
		memset(buf , 0 , sizeof(buf));
	}

	for (i = 0; i < SIZE; i++)
	{
		printf("Please intput ” str str str“\n:");
		scanf("%s %s %s", &stu[i].name, &stu[i].num, &stu[i].age);
	}
	if (fwrite())
	{
		fread();
	}
	return 0;
}

 

运行结果: 

 

 

查看文件中数据存储的格式:

//可以另一种形式看出文件存储的方式。
void freadS(int size)
{
	FILE *fp = NULL; 
	int len = 0, tmp = 1;
	char buffer[1000];
	/*memset(buffer, 1, 100); */
	if ((fp = fopen("text.txt", "r")) == 0)
	{
		printf("open failed!");
		return;
	}
	fseek(fp, 0L, SEEK_END);
	len = ftell(fp);//是四个结构体的字节数
	fseek(fp, 0L, SEEK_SET);
	if(fread(buffer, 1, len, fp) !=  len)
        {
            return ;
        }
	for (int i = 0; i < len; i++)
	{
		printf("%c", buffer[i]);
		
		if (size == tmp)
		{
			printf("\n");
			tmp = 1;
		}
		else
		{
			tmp++;
		}
	}
	fclose(fp);
	printf("\n");
	getchar();
}

freads()运行结果是:

能够很清晰看出存储方式。

函数fseek()

用   法:int fseek(FILE *stream, long offset, int fromwhere)

两个参数的意义分别为:

1、long offset 为偏移量,正数表示正向偏移(向尾部偏移),负数表示负向偏移(向首部偏移); 

2、int fromwhere 为偏移的起始点,对于fromwhere ,函数fseek定义了三个位置,对应如下:

SEEK_SET(对应 0):文件开头;

SEEK_CUR(对应 1):文件指针所指当前位置;

SEEK_END(对应2):文件结尾;

3、返回值:  如果函数执行成功,FILE *stream将指向以fromwhere 为起始点,偏移offset个字节的位置,返回0。若函数执行失败(比如offset超过了文件自身的大小),则不改变stream指向的位置,返回非0值。

若文件偏移超出了文件末尾位置,还是返回0,;若往回偏移超出了文件首部,返回-1,。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值