C语言--文件操作

一、为什么要使用文件

        如果没有⽂件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失 了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的保存,我们可以使⽤ ⽂件。

二、什么是文件

磁盘(硬盘)上的⽂件是⽂件。

但是在程序设计中,我们⼀般谈的⽂件有两种:程序⽂件、数据⽂件(从⽂件功能的⻆度来分类 的)。

程序文件

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

 数据文件

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

本文主要讨论数据文件。

根据数据的组织形式,数据⽂件被称为文本文件或者二进制文件

三、二进制文件和文本文件

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

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

⼀个数据在⽂件中是怎么存储的呢?

        字符⼀律以ASCII形式存储,数值型数据既可以⽤ASCII形式存储,也可以使⽤⼆进制形式存储。

举个栗子:如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),⽽ ⼆进制形式输出,则在磁盘上只占4个字节

四、文件的打开和关闭

4.1  流

        我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出 操作各不相同,为了⽅便程序员对各种设备进⾏⽅便的操作,我们抽象出了流的概念,我们可以把流 想象成流淌着字符的河

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

4.2  标准流

那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?

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

  • stdin-标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据
  • stdout-标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出流中
  • stderr-标准错误流,⼤多数环境中输出到显⽰器界⾯

这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。

4.3  文件指针

        缓冲⽂件系统中,关键的概念是“⽂件类型指针”,简称“⽂件指针”。

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

        每当打开⼀个⽂件的时候,系统会根据⽂件的情况⾃动创建⼀个FILE结构的变量,并填充其中的信 息,⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量,这样使⽤起来更加⽅便。

        下⾯我们可以创建⼀个FILE*的指针变量:

FILE* pf;// ⽂件指针变量

定义pf是⼀个指向FILE类型数据的指针变量。可以使pf指向某个⽂件的⽂件信息区(是⼀个结构体变 量)。通过该⽂件信息区中的信息就能够访问该⽂件。也就是说,通过⽂件指针变量能够间接找到与 它关联的⽂件

4.4  文件的打开和关闭

⽂件在读写之前应该先打开⽂件,在使⽤结束之后应该关闭⽂件

ANSI C规定使⽤ fopen 函数来打开⽂件, fclose 来关闭⽂件

 //打开⽂件 
 FILE * fopen ( const char * filename, const char * mode );
 //关闭⽂件
 int fclose ( FILE * stream );

mode表⽰⽂件的打开模式,下⾯都是⽂件的打开模式:

举个例子:

五、文件的顺序读写

5.1顺序读写函数介绍

1)fputc(): 用于向文件中写入一个字符。                                                                                          函数原型为:int fputc(int c, FILE *stream);

c: 要写入的字符的ASCII码。

stream: 指向要写入的文件的指针。

返回值为写入成功的字符的ASCII码,若写入失败则返回EOF。

2)fgetc(): 用于从文件中读取一个字符。                                                                                           函数原型为:int fgetc(FILE *stream);

.stream: 指向要读取的文件的指针。

返回值为读取到的字符的ASCII码,若到达文件结尾则返回EOF

优化一下:

3)fputs(): 用于向文件中写入一个字符串。                                                                                            函数原型为:int fputs(const char *str, FILE *stream);

str: 要写入的字符串。

stream: 指向要写入的文件的指针。

返回值为写入成功的非负整数,若写入失败则返回EOF。

 

4)fgets(): 用于从文件中读取一行字符串。                                                                                         函数原型为:char *fgets(char *str, int size, FILE *stream);

str: 字符串指针,用于存储读取到的字符串。

size: 最多读取的字符数,包括结尾的'\0'。

stream: 指向要读取的文件的指针。

返回值为成功读取到字符串的指针,若到达文件结尾则返回NULL。

 

5)fprintf

        函数原型为:int fprintf ( FILE * stream, const char * format, ... );

以格式化的形式向流(stream)中输出数据

成功后,将返回写入的字符总数

如果发生写入错误,则设置错误指示器(ferror)并返回负数。

6)fscanf

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

以格式化的形式从流(stream)中读取数据。

成功后,该函数返回成功填充的参数列表的项数。此计数可以与预期的项目数匹配,也可以由于匹配失败、读取错误或文件末尾的到达而减少(甚至为零)。

如果发生读取错误或在读取时到达文件末尾,则会设置正确的指示器(feof 或 ferror)。并且,如果在成功读取任何数据之前发生任一情况,则返回 EOF。

5.2对比函数

scanf / fscanf / sscanf

printf / fprintf / sprintf

scanf:int scanf ( const char * format, ... );

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

sscanf:int sscanf ( const char * s, const char * format, ...);

scanf -  从标准输出流上读取格式化的数据

fscanf - 从指定输出流上读取格式化的数据

sscanf - 从字符串中读取格式化的数据

printf:int printf ( const char * format, ... );

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

sscanf:int sprintf ( char * str, const char * format, ... );

printf - 把数据以格式化的形式打印在标准输出流

fprintf - 把数据以格式化的形式打印在指定输出流

sprintf - 把格式化的数据转换成字符串

5.3 fwrite

        函数原型:size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

以二进制的形式将ptr存储的数据写入流中,一共写入count个元素,每个元素的大小为size字节。

返回成功写入的元素总数。

如果此数字与 count参数不同,则写入错误阻止函数完成。在这种情况下,将为流设置错误指示器(ferror)。

如果sizecount为零,则该函数返回零,错误指示器保持不变。

5.3 fread

        函数原型:size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

以二进制的形式从流中读取count个元素,每个元素的大小为size字节,并将它们存储在 ptr 指定的内存块中。

返回成功读取的元素总数。

如果此数字与count参数不同,则表示读取时发生读取错误或到达文件末尾。在这两种情况下,都会设置正确的指标,可以分别用 ferror 和 feof 进行检查。

如果sizecount为零,则该函数返回零,并且流状态和 ptr 指向的内容保持不变。

六、文件的随机读写

6.1 fseek

        函数原型:int fseek ( FILE * stream, long int offset, int origin );        

根据文件位置和偏移量来定位文件指针(⽂件内容的光标)。

offset为偏移量

origin为起始位置,有三种取值:

SEEK_SET:文件起始位置

SEEK_CUR:文件指针的当前位置

SEEK_END:文件末尾

6.2 ftell

        函数原型:long int ftell ( FILE * stream );

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

6.3 rewind

        函数原型:void rewind ( FILE * stream );

让⽂件指针的位置回到⽂件的起始位置

七、文件读取结束判定

7.1  被错误使⽤的feof

牢记在文件读取的过程中,不能使用feof函数的返回值直接来判断文件是否结束

feof的作⽤是:当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到⽂件尾结束

文件读取结束了,但是是什么原因让读取结束的呢?

feof:读到了文件末尾

ferror:读取的时候发生了错误

文本文件读取:

  • fgetc 判断是否为 EOF .
  • fgets 判断返回值是否为 NULL .

 fgetc - 如果读取正常,返回的是读取到字符的ASCII码值

            如果读取的过程中遇到文件末尾,或者发生错误就返回EOF

fgets - 如果读取正常,返回的是存储读取到的字符数组的地址

            如果读取的过程中遇到文件末尾,或者发生错误,返回NULL

二进制文本读取:

        判断返回值是否⼩于实际要读的个数。

举个栗子:

本文到这里就结束了,如有问题欢迎指导!

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值