C语言-文件读写操作

一、基本概念:

1、文件流:

C 语言把文件看作是一个字符的序列,即文件是由一个一个字符组成的字符流,因此 c 语言将文件也称之为文件流。

即当读写一个文件时,可以不必关心文件的格式或结构。

2、文本文件和二进制文件:

计算机文件的存储,物理上都是二进制,所以文本文件与二进制文件的区别并不是物理上的, 而是逻辑上的。这两者只是在编码层次上有差异。简单来说,文本文件是基于字符编码的文件,常见的编码有 ASCII 编码,二进制文件是基于值编码的文件。

3、文件缓冲:

文件缓冲区(buffer) 存在的好处:首先,缓冲区在内存中,从内存中读取数据比从文件(硬盘)中读取数据要快得多。
其次,对文件的读写需要用到 fopen、fread、fwrite 等系统底层函数,而用户进程每调用一次系统函数都要从用户态切换到内核态,等执行完毕后再返回用户态,这种切换要花费一定时间成本(对于高并发程序而言,这种状态的切换会影响到程序性能)。

刷新缓存区:可以使用 fflush()。


二、文件操作

1、文件的打开和关闭:

 1)打开fopen()      声明 FILE * fopen ( const char * filename, const char * mode );

     mode详解:

 2)关闭fclose()      声明 int fclose ( FILE * stream );

                                成功返回0,失败返回EOF(-1)。

2、文件的读取和写入(文本操作)

1)一次读写一个字符

      写入 fputc()      声明 int fputc (int ch, FILE * stream );      写入成功返回写入的字符,失败返回EOF。

      读取 fgetc()      声明 int fgetc ( FILE * stream );                正常,返回读取的字符;读到文件尾或出错时,为 EOF。

      读取字符,重点是判断结束条件是什么?通常的做法是依据返回值判断。

2)一次读写一行字符

什么是行: 

      行是文本编辑器中的概念,文件流中就是一个字符,不同的平台有差异。

      换行符在window 平台是'\r\n',在linux 平台是'\n'。

平台差异:

①linux 读 windows 中的换行,会多读一个字符,windows 读 linux 中的换行,则没有问题。

      解决:dos2unix 命令

②Linux 中无论使用 gedit 还是 vim ,系统都会自动在末行添加\n 标志。Windows 当中系统不会自动添加\n。

      写入 fputcs()      声明 int fputs(char *str,FILE *fp);          正常,返 0;出错返 EOF。

      读取 fgetcs()      声明 char *fgets(char *str,int length,FILE *fp);   

                                正常,返 str 指针;出错或遇到文件结尾返空指针 NULL。

3、详解 fgetcs() :

从 fp 所指向的文件中,至多读 length-1 个字符,送入字符数组 str中, 如果在读入 length-1 个字符结束前遇\n 或 EOF,读入即结束,字符串读入后在最后加一个‘\0’字符。
       fgets 函数返回有三个条件:
      1)读 length-1 个字符前遇到\n,读取结束(\n 被读取) + \0。
      2)读 length-1 个字符前遇到 EOF,读取结束 +\0。
      3)读到length-1 个符 +\0。

4、文件的读写(二进制操作)----一次读写一块数据

 C 语言所有的文件接口函数,要么以 '\0',表示输入结束,要么以 '\n', EOF(0xFF)表示读取结束,这些都是文本文件的重要标识。而二进制文件,则往往以块的形式,写入或读出。所有的二进制接口对于这些标识,是不敏感的,把它们当做普通字符处理。

      写入 fwrite    声明 int fwrite(void *buffer, int num_bytes, int count, FILE *fp);

      读取 fread    声明int fread(void *buffer, int num_bytes, int count, FILE *fp);

                           返回值:   成功,返回读/写的字段数;出错或文件结束,返回 0。

注意 fread返回值陷阱:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main(void)
{
	FILE *fpw = fopen("bin.txt", "wb+");
	if (fpw == NULL)
	{
		return -1;
	}
	char *p = "123456789";
	fwrite(p, 1, strlen(p), fpw);
	rewind(fpw);
	char buf[1024];
	int n;
	//错误读法  4+4+0
	n =fread((void*)buf,4,1,fpw);
	printf("n = %d\n",n);
	n =fread((void*)buf,4,1,fpw);
	printf("n = %d\n",n);
	n =fread((void*)buf,4,1,fpw);	//按块读取,不够4个导致出错
	printf("n = %d\n",n);

	//正确读法  4+4+1
	/*n = fread((void*)buf, 1, 4, fpw);
	printf("n = %d\n", n);
	n = fread((void*)buf, 1, 4, fpw);
	printf("n = %d\n", n);
	n = fread((void*)buf, 1, 4, fpw);
	printf("n = %d\n", n);*/
	return 0;
}

分析:fread  依靠读出块的多少来标识读结果和文件结束标志。因此读取时最好以最小的单元格式进行读,或是以写入的最小单元进行读。

5、文件指针偏移函数:

1、rewind()   声明 void rewind ( FILE * stream );      将文件指针重新指向一个流的开头。

用途:如果一个文件具有读写属性,则我们写完文件时,文件指针指向结尾,当需要读取时就需要 rewind函数。

2、ftell()        声明 long ftell ( FILE * stream );     

                      成功,返回当前读写位置偏离文件头部的字节数。失败, 返回-1。

3、fseek()     声明 int fseek ( FILE * stream, long offset, int where);      偏移文件指针

                      成功返回 0 ,失败返回-1。

   常见起始位置宏定义:

#define SEEK_SET 0     //文件开头
#define SEEK_CUR 1     //当前位置
#define SEEK_END 2     //文件结尾

/*简单用法*/
fseek(fp,100L,0);     //把 fp 指针移动到离文件开头 100 字节处;
fseek(fp,100L,1);     //把 fp 指针移动到离文件当前位置 100 字节处;
fseek(fp,-100L,2);    //把 fp 指针退回到离文件结尾 100 字节处。

三、总结:

前面简单介绍了文本读写和二进制读写,但归根到底二进制读写才是本质。

1、使用二进制读取功能更加强大,比如读取结构体就非常适合,结构体包含各种类型,类型大小不一,使用二进制就不需要考虑这些问题。

2、文件读写特别注意如何判断是否读取成功,是否写入完成,一般使用返回值判断。

3、读以下文件,请问 fgets 共执行了多少次?

     fgets( buf, 10, fp) ;

           1234567890abcdefg(换行)
           1234567890(换行)
           abcdefg(EOF)

分析:fgets 共执行了5次,length为10,所以每次最多读10-1 = 9个字符。

          第一次,读到1~9    +\0      第二次,读到0~g  \n   +\0      第三次,读到1~9    +\0

          第四次,读到0   \n   +\0     第五次,a~g    +\0

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值