C语言文件操作

1:在程序设计中为什么要使用文件?

文件可以将数据持久化的保存,如果不使用文件,我们写的程序的数据是保存在电脑的内存中,如果程序退出,内存回收,数据就会丢失。

2:文件及其分类

   磁盘(外存)上的文件就是所说的文件

   从文件的功能角度:可分为程序文件数据文件。

             程序⽂件:包括源程序⽂件(后缀为.c),⽬标⽂件(windows环境后缀为.obj),可执⾏程序(windows 环境后缀为.exe)。

            数据文件:⽂件的内容不⼀定是程序,⽽是程序运⾏时读写的数据,⽐如程序运⾏需要从中读取数据的⽂件,或者输出内容的⽂件

     从文件的组织形式角度:可分为文本文件二进制文件 

            二进制文件:数据在内存中以⼆进制的形式存储,如果不加转换的输出到外存的⽂件中,就是⼆进制⽂件。

            文本文件:如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的⽂件就是⽂本⽂件。

     以 10000(十进制)在文本文件和二进制文件中的储存为例:

3:文件的打开和关闭

    1)流和标准流

          1.1)流

                   我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出操作各不相同,为了⽅便程序员对各种设备进⾏⽅便的操作,我们抽象出了流的概念。

通过以下图片可以了解流带来的好处:

a:

b:

*可以看出,抽象出流的概念后,易于程序员对文件的读写操作

*C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作都是通过流操作的。⼀般情况下,我们要想向流⾥写数据,或者从流中读取数据,都是要打开流,然后操作。

          1.2)标准流

                     C语⾔程序在启动的时候,默认打开了3个流:

                     • stdin-标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中                         读取数据。

                     • stdout-标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出                          到标准输出流中。

                     • stderr-标准错误流,⼤多数环境中输出到显⽰器界⾯。 这是默认打开了这三个流,                          我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。

                     *并且因为 C语⾔程序在启动的时候,默认打开了这3个流。我们在写C语言程序时能                         直接从键盘输入数据,并在屏幕上显示数据,甚至在能进行代码报错

    2)文件指针

           每个被使⽤的⽂件都在内存中开辟了⼀个相应的文件信息区,⽤来存放⽂件的相关信息(如⽂件的名字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系统声明的,取名FILE。

            ⼀般都是通过⼀个FILE的指针(类型为:FILE* )来维护这个FILE结构的变量,这样使用起来更加⽅便。

画图理解:

      3):文件的打开和关闭

             对文件进行操作时必须先打开文件,在进行读写操作,最后一定要关闭文件

            3.1):fopen和fclose函数

                       fopen:

                                  格式:FILE * fopen ( const char * filename, const char * mode )

                                           filename为文件名,mode表示文件打开模式

                                  功能:打开文件

                                  返回值:若成功打开文件,则返回一个FILE*的指针;

                                                 若打开失败,则返回NULL

                      fclose:

                                功能:刷新Stream所指向的流,并关闭文件

                                格式:int fclose ( FILE * stream )

                                返回值:若成功关闭,则返回0;

                                               否则返回EOF

             3.2):文件的打开模式

(还有其它模式,这里就不一一列举了)

⽂件使⽤⽅式            含义                                                                    如果指定⽂件不存在 

“r”(只读)               为了输⼊数据,打开⼀个已经存在的⽂本⽂件    出错

“w”(只写)              为了输出数据,打开⼀个⽂本⽂件                      建⽴⼀个新的⽂件

“a”(追加)              向⽂本⽂件尾添加数据                                         建⽴⼀个新的⽂件

“rb”(只读)             为了输⼊数据,打开⼀个⼆进制⽂件                   出错

“wb”(只写)           为了输出数据,打开⼀个⼆进制⽂件                    建⽴⼀个新的⽂件

“ab”(追加)            向⼀个⼆进制⽂件尾添加数据                              建⽴⼀个新的⽂件

              3.3):文件操作的基本格式
/* fopen fclose example */
 #include <stdio.h>
 int main ()
 {
  FILE * pFile;

  //打开⽂件
  pFile = fopen ("myfile.txt","w");

  if (pFile == NULL)
  {
    printf("打开失败");
    return -1;
  }

  //进行文件操作
  fputs("abcdef", pFile);

  //关闭文件
  fclose(pFile);

  return 0;
 }

4:文件的顺序读取

 文件顺序读取函数(每次读取成功后,再次调用函数会从下一个位置开始读取):

fgetc,fputc,fgets,fputs,fscanf,fprintf,fread,fwrite

函数                  功能                             适⽤于

fgetc                  字符输⼊函数              所有输⼊流

fputc                  字符输出函数              所有输出流

fgets                  ⽂本⾏输⼊函数          所有输⼊流

fputs                  ⽂本⾏输出函数          所有输出流

fscanf                格式化输⼊函数          所有输⼊流

Fprintf               格式化输出函数           所有输出流

fread                 ⼆进制输⼊                  ⽂件输⼊流

fwrite                 ⼆进制输出                 ⽂件输出流

1)fgetc

格式:int fgetc(FILE* Stream)

功能:从Stream指向的文件中读取字符,每次只读取一个字符

返回值:若读取成功则返回成功读取字符的ASCII码;

              若遇到文件末尾或读取失败则返回EOF(文件结束的标致,值为 -1)

代码演示:

2)fputc

格式:int fputc(int Character, FIEL* Stream)

功能:将指定字符(ASCII码为Character)写入到Stream指向的文件

返回值:若写入成功,则返回指定字符的ASCII;

              若写入失败则返回EOF

代码演示:

3)fgets

格式:char* fgets(char* Buffer, int Maxcount, FILE* Stream)

功能:从Stream指向的文件中读取字符写入Buffer指向的内存空间,并且最多向该内存空间写入长度为Maxcount - 1 的字符串。

返回值:若读取成功则返回Buffer;

              若读取失败或遇到文件末尾则返回NULL

具体说明:

注意:Buffer指向内存空间的大小一定要大于等于Maxcount个字节,否则会发生缓冲区溢出

       a:fgets函数可以简单理解为每次读取一行数据

       b:当从Stream指向的文件读取的字符个数(以’\n’作为读取结束的标志)大于等于Maxcount - 1 时,则会将第Maxcount - 1个字符后加上 ’\0’ 后组成的字符串写入Buffer指向的内存空间

      c:当从Stream指向的文件读取的字符个数(以’\n’作为读取结束的标志)小于Maxcount - 1 时,会将在读取到的最后一个字符,即’\n’,后加上’\0’后组成的字符串写入Buffer指向的内存空间

代码演示:

4)fputs

格式:int fputs(char* Buffer, FILE* Stream)

功能:将Buffer指向内存空间的字符串写入到Stream指向的文件中,而不会自动写入字符串结束符’\0’。注意Buffer指向的内存空间中一定要含有’\0’,当Buffer指向内存空间没有’\0’时,就会向Stream指向的文件中写入其他字符直至遇到’\0’

返回值:若写入成功,则返回一个非负数;

               若写入失败,则返回EOF

代码演示:

5)fscanf

格式:int fscanf(FILE* Stream, const char* const Format, . . . )

功能:从Stream指向的文件中格式化读取数据存放在指定变量里,和scanf函数类似

返回值:若读取成功,则返回输入项数;

        若只成功读取部分数据,则返回成功读取的项数;

        若没执行任何转换就发生错误,则返回EOF

代码演示:

6)fprintf

格式:int fprintf(FILE* Stream, const char* const Format, . . . )

功能:向Stream指向的文件中格式化写入数据,和printf函数类似

返回值:返回写入的字符数;

               若写入错误则返回负值

代码演示:

7)fread

格式:size_t fread(void* Buffer, size_t ElementSize, size_t ElementCount, FILE* Stream)

功能:从Stream指向的文件(指向二进制文件)中读取 ElementCount个元素大小为ElementSize个字节的数据,并写入Buffer指向的内存空间

返回值:返回实际读取的元素元素个数;

              若返回值小于ElementCount,则可能是遇到文件结尾或发生错误

代码演示:

再使用fread函数从该二进制文件中读取数据,代码如下:

8)fwrite

格式:size_t fwrite(void* Buffer, size_t ElementSize, size_t ElementCount, FILE* Stream)

功能:从Buffer指向的内存空间读取 ElementCount个元素大小为ElementSize个字节的数据,并写入Stream指向的文件中

返回值:返回实际写入的项数;

              若返回值小于ElementCount,则可能是遇到文件结尾或发生错误

代码演示:

5:文件的随机读写

文件随机读取函数:

1)fseek

格式:int fseek(FILE* Stream, long Offset, int Origin)

功能:重新定位文件指针,使文件指针指向Origin位置偏移Offset个字节后的位置

返回值:若定位成功,则返回0

               否则返回其他值

具体说明:

Origin可取:SEEK_SET:指文件指针的起始位置

           SEEK_CUR:指文件指针的当前位置

           SEEK_END:指文件末尾

代码演示:

2)ftell

格式:long ftell(FILE* Stream)

功能:返回文件指针相对于起始位置的偏移量;

返回值:文件指针相对于起始位置的偏移量

代码演示:

3)rewind

格式:void rewind(FILE* Stream)

功能:让文件指针回到起始位置

返回值:void

代码演示:

6:文件读取结束的判断

EOF、feof、ferror

EOF为文本文件结束的结束标致,而feof, ferror函数则是用来在文件结束后,判断文件结束的原因

1)EOF

EOF作为文本文件的结束标志,在文本文件中,数据都是以ASCII码值的形式存放。fgetc, fputc等函数在读取文本文件时函数的返回值为对应字符的ASCII码值,而ASCII码值的取值范围为:0~127,所以EOF(值为-1)可以作为文件结束或写入错误的标致

代码演示:

2)feof

格式:int feof(FILE* Stream )

功能:判断文件结束的原因是遇到文件末尾还是发生错误

返回值:若返回非零值,则代表遇到文件末尾;

               否则返回零

代码演示:

3)ferror

格式:int ferror(FIEL* Stream)

功能:检查是否设置了与流相关联的错误标识,来判断文件结束的原因是遇到文件末尾还是发生错误

返回值:若返回非零值,则代表成功设置了与流相关联的错误标识,文件结束的原因为发生错误;

              否则返回0

代码演示:

注意:对同一文件每次调用输入输出函数,均会产生一个新的ferror函数值,所以应当在调用一个输入输出函数后立即检查ferror函数的值,否则信息会丢失。在执行fopen函数时,ferror函数的初始值自动置为0

7:文件缓冲区

ANSIC标准采⽤“缓冲⽂件系统”处理数据⽂件,所谓缓冲⽂件系统是指系统⾃动地在内存中为 程序中每⼀个正在使⽤的⽂件开辟⼀块“⽂件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才⼀起送到磁盘上。如果从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输⼊到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的⼤⼩根据C编译系统决定的。

画图理解:

代码演示:

#include <windows.h>
#include <stdio.h>
int main() {
	FILE* pf = fopen("test.txt", "w");
	fputs("abcdef", pf);
	//将"abcdef"输入输入缓冲区
	//10秒内test.txt文件中没有出现"abcdef"
	// 说明缓冲区没有被装满,
	// "abcdef"也就没有被输入到外存设备
	printf("睡眠10秒,请打开并观察test.txt文件,发现没有 abcdef,请关闭test.txt\n");
	Sleep(10000);
	//刷新缓冲区,将"abcdef"输入到外存设备
	fflush(pf);
	printf("请重新打开并观察test.txt文件,发现有 abcdef\n");
	//再次睡眠10秒,排除fclose函数刷新缓冲区的可能
	Sleep(10000);
	fclose(pf);
	pf = NULL;
	return 0;
}

*在两次提示打开并观察test.txt文件时,及时打开文件并进行观查。发现第一次无"abcdef"而第二次有"abcdef",说明缓冲区确实存在。

         

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值