欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

C语言文件操作(详解)(一)

最编程 2024-08-13 09:14:14
...

数据流和缓冲区是什么?

在C语言中,将在不同的输入/输出设备之间进行传递的数据抽象为“流”。

流实际上就是一个字节序列,输入函数的字节序列被称为输入流,输出函数的字节序列称为输出流。

根据数据形式,输入输出流可以分为 文本流(字符流)二进制流

  • 数据流 是指程序与数据的交互是以流的形式进行的。进行C语言文件的存取时,都会先进行“打开文件”操作,这个操作就是在打开数据流,而“关闭文件”操作就是关闭数据流。
  • 缓冲区(Buffer) 是指程序执行时所提供的额外内存,可用来暂时存放做准备执行的数据。它的设置是为了提高存取效率,因为内存的存取速度比磁盘驱动器快得多。
    C语言中带缓冲区的文件处理:当使用标准I/O函数(包含在头文件stdio.h中)时,系统会自动设置缓冲区,并通过数据流来读写文件。当进行文件读取时,不会直接对磁盘进行读取,而是先打开数据流,将磁盘上的文件信息拷贝到缓冲区内,然后程序再从缓冲区中读取所需数据当写入文件时,并不会马上写入磁盘中,而是先写入缓冲区,只有在缓冲区已满或“关闭文件”时,才会将数据写入磁盘

一、为什么使用文件?

在C语言中,使用文件的主要原因是为了实现数据的持久化存储和共享。文件是一种用于存储和读取数据的常见方式,它可以保存各种类型的数据,包括文本、图像、音频、视频等。

通过使用文件,程序可以实现以下功能:

  1. 数据持久化:程序可以将数据写入文件,以便在程序关闭后仍然可以读取和访问这些数据。这对于需要保存用户设置、配置信息或临时数据等非常有用。
  2. 数据共享:文件可以用于在不同的程序或系统之间共享数据。例如,一个程序可以生成一个包含分析结果的报告文件,另一个程序可以读取该文件以获取所需的信息。
  3. 备份和恢复:通过将数据写入文件,程序可以定期备份数据,并在需要时从备份中恢复。这有助于确保数据的完整性和可靠性。
  4. 外部数据访问:对于一些需要与外部系统交互的程序,文件可以作为不同系统之间的桥梁。例如,一个程序可以通过读取外部传感器生成的日志文件来获取数据。

总之,使用文件为C语言程序提供了持久化存储、数据共享、备份和恢复以及外部数据访问等功能,这些功能对于实现程序的灵活性和可扩展性非常重要。


二、什么是文件

在C语言中,文件被看作是数据源的一种。它能够存储在磁盘或其他存储设备上,提供了一种便捷的方式来读取和写入数据。(即磁盘上的文件是文件

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

2.1 程序文件

包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。

2.2 数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件

本章讨论的是数据文件。

在学习文件操作之前处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。

其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上文件。

2.3 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。

文件名包含3部分:文件路径+文件名主干+文件后缀

网络异常,图片无法展示
|


三、文件的打开和关闭

3.1 文件指针

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

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

例如,VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

struct _iobuf {
    char* _ptr;
    int   _cnt;
    char* _base;
    int   _flag;
    int   _file;
    int   _charbuf;
    int   _bufsiz;
    char* _tmpfname;
};
typedef struct _iobuf FILE;

不同的C编译器的 FILE 类型包含的内容不完全相同,但是大同小异。

每当打开一个文件的时候,系统会根据文件的情况 自动创建 一个 FILE 结构的变量,并填充其中的信息,使用者不必关心细节。

一般都是通过一个 FILE 的指针来维护这个 FILE 结构的变量,这样使用起来更加方便。

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

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

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

例如:

网络异常,图片无法展示
|

3.2 文件的打开和关闭(fopen和fclose)

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

在编写程序的时候,在打开文件的同时,都会返回一个 FILE* 的指针变量指向该文件,也相当于建立了指针和文件的关系。

ANSIC 规定使用 fopen 函数来打开文件,fclose 来关闭文件。

3.2.1 fopen

函数声明:

//打开文件
FILE * fopen ( const char * filename, const char * mode );

参数

  • filename - - - 字符串,表示要打开的文件名称。
  • mode - - - 字符串,表示文件的访问模式,可以是以下表格中的值:
文件使用方式 含义 如果指定文件不存在
“r”(只读) 为了输入数据,打开一个已经存在的文本文件 出错
“w”(只写) 为了输出数据,打开一个文本文件 建立一个新的文件
“a”(追加) 向文本文件尾添加数据 建立一个新的文件
“rb”(只读) 为了输入数据,打开一个二进制文件 出错
“wb”(只写) 为了输出数据,打开一个二进制文件 建立一个新的文件
“ab”(追加) 向一个二进制文件尾添加数据 出错
“r+”(读写) 为了读和写,打开一个文本文件 出错
“w+”(读写) 为了读和写,建议一个新的文件 建立一个新的文件
“a+”(读写) 打开一个文件,在文件尾进行读写 建立一个新的文件
“rb+”(读写) 为了读和写打开一个二进制文件 出错
“wb+”(读写) 为了读和写,新建一个新的二进制文件 建立一个新的文件
“ab+”(读写) 打开一个二进制文件,在文件尾进行读和写 建立一个新的文件

返回值

该函数返回一个 FILE 指针。否则返回 NULL,且设置全局变量 errno 来标识错误。

3.2.2 fclose

函数声明:

//关闭文件
int fclose(FILE *stream);

参数

  • stream - - - 这是指向 FILE 对象的指针,该 FILE 对象指定了要被关闭的流。

返回值

如果流成功关闭,则该方法返回零。如果失败,则返回EOF

实例代码:

/* fopen fclose example */
#include <stdio.h>
int main()
{
    FILE* pFile;
    //打开文件
    pFile = fopen("myfile.txt", "w");
    //文件操作
    if (pFile != NULL)
    {
        fputs("fopen example", pFile);
        //关闭文件
        fclose(pFile);
    }
    return 0;
}


四、 文件的顺序读写

常见的读写函数如下标表所示:

功能 函数名 适用于
字符输入函数 fgetc 所有输入流
字符输出函数 fputc 所有输出流
文本行输入函数 fgets 所有输入流
文本行输出函数 fputs 所有输出流
格式化输入函数 fscanf 所有输入流
格式化输出函数 fprintf 所有输出流
二进制输入 fread 文件
二进制输出 fwrite 文件

4.1 fgetc函数(读一个字符)

C 库函数 int fgetc(FILE *stream) 从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。

声明:

int fgetc(FILE *stream);

参数

  • stream - - - 这是指向 FILE 对象的指针,该 FILE 对象标识了要在上面执行操作的流。

返回值

  • 该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF

4.2 fputc函数(写一个字符)

C 库函数 int fputc(int char, FILE *stream) 把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。

声明:

int fputc(int char, FILE *stream);

参数

  • char - - - 这是要被写入的字符。该字符以其对应的 int 值进行传递。
  • stream - - - 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符的流。

返回值

  • 如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。

4.3 fgets函数(读一行字符串)

C 库函数 char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

声明:

char *fgets(char *str, int n, FILE *stream);

参数

  • str - - - 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
  • n - - - 这是要读取的最大字符数(包括终止空字符)。通常是使用以 str 传递的数组长度。
  • stream - - - 指向标识输入流的 FILE 对象的指针。stdin 可以用作从标准输入读取的参数。

返回值

  • 成功后,函数返回 str
  • 如果在尝试读取字符时 遇到文件末尾,则设置 eof 指示器 (feof)。如果在读取任何字符之前发生这种情况,则返回的指针为空指针(str 的内容保持不变)。
  • 如果发生读取错误,则设置错误指示器(ferror),并返回 空指针(但 str 指向的内容可能已更改)。

4.4 fputs函数(写一行字符串)

C 库函数 int fputs(const char *str, FILE *stream) 把字符串写入到指定的流 stream 中,但 不包括空字符

声明:

int fputs(const char *str, FILE *stream);

参数

  • str - - - 这是一个数组,包含了要写入的以空字符终止的字符序列。
  • stream - - - 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。

返回值

  • 成功时,将返回非负值
    出错时,该函数返回 EOF 并设置错误指示器( ferror)。

4.5 fscanf函数

C 库函数 int fscanf(FILE *stream, const char *format, ...) 从流 stream 读取格式化输入。

声明:

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

该函数与scanf函数类似,只是多了最前面的参数stream- - -指向标识要从中读取数据的输入流的 FILE 对象的指针。若传入的输入流对象为 stdin,则功能与 scanf 一样。

4.6 fprint函数

C 库函数 int fprintf(FILE *stream, const char *format, ...) 发送格式化输出到流 stream 中。

声明:

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

该函数与printf函数类似,只是多了最前面的参数stream- - -指向标识输出流的 FILE 对象的指针。若传入的输出流对象为 stdout,则功能与 scanf 一样。

4.7 fread函数(二进制形式读数据)

C 库函数 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 从给定流 stream 读取数据到 ptr 所指向的数组中。

声明:

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

参数

  • ptr - - - 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
  • size - - - 这是要读取的每个元素的大小,以字节为单位。
  • nmemb - - - 这是元素的个数,每个元素的大小为 size 字节。
  • stream - - - 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。

返回值