前言
在C语言中,文件操作是一项重要的任务。通过文件操作,我们可以读取和写入文件的内容,实现数据的长期存储和共享。文件操作不仅可以用于文本文件,还可以用于二进制文件、配置文件等各种类型的文件。
这篇文章中,我们将深入探讨C语言文件操作的各个方面,介绍常用的文件操作函数和技巧,帮助读者更好地理解和应用文件操作。无论是初学者还是有一定经验的开发者,都能从中获得实用的知识和技能,为自己的C语言编程之路增添新的可能性。
一、文件类型
1. 程序文件
⭕程序文件是包含C源代码的文件,它们经过编译和链接后可以生成可执行程序。程序文件中定义了变量、函数、结构体等程序元素,通过编写相应的代码实现所需的功能。在程序文件中,我们可以使用各种控制结构、输入输出函数和库函数来操作和处理数据。
2. 数据文件
⭕数据文件是包含实际数据的文件,可以是文本文件或二进制文件。文本文件以可读的文本形式存储数据,可以使用标准的输入输出函数(如printf和scanf)来读取和写入文本文件。二进制文件以二进制形式存储数据,一般需要使用专门的读写函数进行处理。
PS.文件名
一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀。 例如: c:\code\test.txt
为了方便起见,文件标识常被称为文件名。
二、文件的打开和关闭
1. 文件指针
文件指针是C语言中用于定位和访问文件的机制。它是一个特殊的变量,用来指示当前操作的位置或位置的偏移量。通过文件指针,我们可以进行读写操作,并在文件中移动指针的位置。
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名FILE.
struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; }; typedef struct _iobuf FILE;
不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异
文件指针的位置决定了下一次读写操作的位置。例如,在读取文件内容时,每次读取前文件指针会自动后移,以便下次读取从下一个位置开始。
另外,文件指针还有几个重要的特殊位置:
- 文件起始位置(0):文件打开后,文件指针通常位于文件起始位置,即偏移量为0的位置。
- 文件末尾位置(EOF):表示文件的结尾,文件指针在读取到文件末尾时会自动停止读取操作。
- 文件错误位置(NULL):在发生错误时,文件指针可能为NULL,表示无法继续操作文件。
在使用文件指针时,我们需要注意一些常见的问题。首先,操作文件前必须确保文件已经成功打开,并在使用完毕后及时关闭文件,以便释放资源。其次,应注意异常情况的处理,如文件不存在、权限不足等,以避免程序崩溃或产生错误结果。
2. 文件的打开和关闭
文件的打开和关闭是文件处理中非常重要的操作。在进行文件读写时,必须先打开文件,然后进行读写操作,最后再关闭文件。这样做可以避免文件资源泄漏和数据损坏等问题。在C语言中,文件的打开和关闭可以通过文件操作函数来实现。其中,常用的文件操作函数包括fopen
、fclose
等。下面是一个基本的文件打开和关闭的示例:
#include <stdio.h> int main() { FILE *fp; char filename[20]; // 打开文件 printf("请输入要打开的文件名:"); scanf("%s", filename); fp = fopen(filename, "r"); if (fp == NULL) { printf("文件打开失败!\n"); return 1; } printf("文件打开成功!\n"); // 文件读取或写入操作… // 关闭文件 fclose(fp); printf("文件已关闭!\n"); return 0; }
上述代码中,我们首先定义了一个指向文件的指针(FILE *fp
),然后通过fopen
函数打开文件。fopen
函数的第一个参数是文件名或路径(字符串类型),第二个参数是打开文件的模式(字符串类型)。文件打开模式包括:
文件使用方式 | 含义 | 如果指定文件不存在 |
“r” (只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
“w” (只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
“a” (追加) | 向文本文件尾添加数据 | 建立一个新的文件 |
“rb” (只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb” (只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
“ab” (追加) | 向一个二进制文件尾添加数据 | 出错 |
“r+” (读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+” (读写) | 为了读和写,建议一个新的文件 | 建立一个新的文件 |
“a+” (读写) | 打开一个文件,在文件尾进行读写 | 建立一个新的文件 |
“rb+” (读写) | 为了读和写打开一个二进制文件 | 出错 |
“wb+” (读写) | 为了读和写,新建一个新的二进制文件 | 建立一个新的文件 |
“ab+” (读写) | 打开一个二进制文件,在文件尾进行读和写 | 建立一个新的文件 |
在打开文件后,我们可以进行读写操作。最后通过fclose
函数关闭文件,以释放资源。如果在打开文件时出现错误,则返回的指针为NULL
,需要进行错误处理。
三、文件的顺序读写
当打开文件时,可以通过指定不同的访问模式来控制文件读写的方式。在选择读写模式后,就可以使用文件指针进行读写操作。
⭕常见的读写函数有:
功能 | 函数名 | 适用于 |
字符输入 | fgetc | 所有输入流 |
字符输出 | fputc | 所有输出流 |
文本行输入 | fgets | 所有输入流 |
文本行输出 | fputs | 所有输出流 |
格式化输入 | fscanf | 所有输入流 |
格式化输出 | fprintf | 所有输出流 |
二进制输入 | fread | 文件 |
二进制输出 | fwrite | 文件 |
下面是一个示例代码,用于在文本文件中按顺序读取和写入数据:
#include <stdio.h> int main() { FILE *fp = fopen("example.txt", "r"); char str[255]; if (fp == NULL) { printf("Error opening file\n"); return -1; } // 读取每一行并输出 while (fgets(str, 255, fp) != NULL) { printf("%s", str); } fclose(fp); // 向文件中写入数据 fp = fopen("example.txt", "a"); if (fp == NULL) { printf("Error opening file\n"); return -1; } fprintf(fp, "This is a new line\n"); fclose(fp); return 0; }
该示例程序首先以只读模式打开文件 example.txt
,然后使用 fgets
函数按照行读取数据并输出。接着,它再以追加模式打开同一个文件,并使用 fprintf
函数向文件中写入一行新数据。
四、文件的随机读写
1. fseek() 函数
fseek
是一个用于设置文件指针位置的函数。它的原型如下:
int fseek(FILE *stream, long offset, int origin);
参数说明:
stream
:指向要设置位置的文件流的指针。offset
:要添加到或减去当前位置的字节数,可以是正数或负数。origin
:用于确定offset
如何解释的常量。可以使用以下值之一:
- SEEK_SET:从文件开头开始计算偏移量。
- SEEK_CUR:从当前位置开始计算偏移量。
- SEEK_END:从文件末尾开始计算偏移量。
返回值为 0 表示成功,非零值表示出错。
使用 fseek
可以将文件指针定位到文件中的任意位置进行读写操作。例如,要将文件指针定位到文件开头,可以使用如下代码:
FILE *fp = fopen("example.txt", "r"); if (fp == NULL) { printf("Error opening file\n"); return -1; } // 将文件指针设置到文件开头 fseek(fp, 0, SEEK_SET); // 在此处进行读取操作 fclose(fp);
在上述代码中,我们打开了一个名为 example.txt
的文件,并将文件指针通过 fseek
函数定位到了文件的开头位置。
2. ftell() 函数
ftell
是一个用于获取文件指针当前位置的函数。它的原型如下:
long ftell(FILE* stream);
参数 stream
是指向要获取当前位置的文件流的指针。返回值是当前位置相对于文件开头的字节数(偏移量)。
以下是一个示例代码,演示了如何使用 ftell
函数获取文件指针的当前位置:
#include <stdio.h> int main() { FILE *fp = fopen("example.txt", "r"); if (fp == NULL) { printf("Error opening file\n"); return -1; } // 定位到文件第6个字节的位置 fseek(fp, 5, SEEK_SET); // 获取文件指针的当前位置 long position = ftell(fp); printf("Current position: %ld\n", position); fclose(fp); return 0; }
在上述示例中,我们首先打开一个名为 example.txt
的文件,并使用 fseek
将文件指针定位到文件的第6个字节处。然后,通过调用 ftell
函数获取文件指针的当前位置,并将其打印出来。
🚨🚨注意:ftell
返回的是一个 long
类型的值,表示当前位置相对于文件开头的字节数。如果发生错误,ftell
可能会返回一个特殊的值 EOF
(-1)。因此,在使用 ftell
的结果时,应该先检查是否出错。
3. rewind() 函数
rewind
是一个用于将文件指针重新定位到文件开头的函数。它的原型如下:
void rewind(FILE *stream);
参数 stream
是指向要重新定位的文件流的指针。rewind
函数会将文件指针移动到文件开头,即相当于调用 fseek(stream, 0, SEEK_SET)
。
以下是一个示例代码,演示了如何使用 rewind
函数将文件指针重新定位到文件开头:
#include <stdio.h> int main() { FILE *fp = fopen("example.txt", "r"); if (fp == NULL) { printf("Error opening file\n"); return -1; } // 将文件指针重新定位到文件开头 rewind(fp); // 在此处进行读取操作 fclose(fp); return 0; }
在上述示例中,我们打开一个名为 example.txt
的文件,然后使用 rewind
将文件指针重新定位到文件开头。这样,在之后的读取操作中,可以从文件的开头开始读取数据。
总结
本文介绍了 C 语言中文件操作的基础知识,包括文件类型、文件的打开和关闭、文件的顺序读写和随机读写等。文章首先将文件分为程序文件和数据文件两种类型,并简要说明了它们的区别以及命名方式。接下来,文章详细讲解了文件的打开和关闭过程,包括如何使用文件指针和相关函数打开文件、关闭文件,以及处理错误情况。在讲解完文件的基础操作后,文章介绍了文件的顺序读写和随机读写两种方式,并提供了相应的函数及示例代码进行演示。其中,随机读写部分还详细介绍了 fseek()、ftell() 和 rewind() 等函数的用法。