1.文件的概念
文件是存储在某种存储介质上的一组数据的集合,它包含了文本、图像、音频或其他类型的数据,并且这些数据被组织和命名,以便用户能够识别和访问。文件的管理和操作对于计算机系统来说至关重要,它们为人们提供了一种方便的方式来保存、检索和共享信息。C语言中的文件是一种数据存储和组织的方式,用于在磁盘上持久化存储信息。C语言通过标准库函数提供文件操作的能力。
(1). 文件的定义
信息集合:文件被定义为存储在计算机硬盘上的信息的集合,这些信息可以是文本文档、图片或程序等。
资源调度:在系统运行时,计算机以进程为基本单位进行资源的调度和分配;而在用户进行的输入、输出中,则以文件为基本单位。
输入输出:大多数应用程序的输入都是通过文件来实现的,其输出也保存在文件中,以便信息的长期存储及将来的访问
(2)文件名
一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
例如: c:\code\test.txt
为了方便起见,文件标识常被称为文件名。
2.常见的文件类型
文件的类型繁多,每种类型都有其特定用途和结构。文件类型通常以扩展名的形式体现,它帮助操作系统和应用程序识别如何正确处理每个文件。
a. 文本文件类型
ASCII: 这是一种简单的文本存储格式,可以在多种操作系统之间无障碍交换。
MIME: 通常用于电子邮件中,定义了文本的“text/plain”类型,并可能包含编码信息。
TXT: 这是最常见的文本文件扩展名,内容为纯文本,不包含复杂的格式或媒体内容。
b. 视频文件格式类型
WMV: 由微软开发,用于流媒体和在线播放的视频格式。
MP4: MPEG-4 Part 14的简称,广泛用于网络视频分享和移动设备上。
AVI: 由微软开发的多媒体容器格式,支持多种编码的视频和音频。
c. 音频文件格式类型
MP3: 广泛使用的音频压缩格式,适合在线流媒体和音乐存储。
WAV: 由微软和IBM开发,常用于保存未压缩的音频文件,提供高质量的音频输出。
OGG: 一种开源的音频压缩格式,与MP3类似但无专利限制。
d. 图片文件格式类型
JPEG: 用于照片和其他连续色调图像的存储格式,支持高压缩率。
PNG: 提供无损压缩,支持透明背景,适合网页图形和图像编辑。
GIF: 常用于简单动画和网页图形,支持256色和透明处理。
e. 可执行文件格式类型
EXE: Windows系统中的可执行程序,用户可以双击运行这些文件来启动应用。
COM: DOS和Windows中的命令文件,通常是简单的可执行程序。
BAT: 批处理文件,包含一系列命令,用于自动执行操作系统任务。
3.文件的操作
(1)文件指针
C语言中的文件指针是一个指向FILE类型的指针,用于操作文件。在C语言中,文件操作是通过文件指针进行的。要使用文件指针,需要先声明一个FILE类型的变量,然后通过fopen()函数打开文件,将返回的文件指针赋值给该变量。接下来,可以使用各种文件操作函数(如fread(), fwrite()等)对文件进行读写操作。最后,使用fclose()函数关闭文件。
#include <stdio.h>
int main() {
// 声明一个文件指针
FILE *fp;
// 以只读模式打开文件
fp = fopen("example.txt", "r");
if (fp == NULL) {
printf("无法打开文件");
return 1;
}
// 关闭文件
fclose(fp);
return 0;
}
(2)文件的打开与关闭
fopen函数是C语言中用于打开文件的标准函数。此函数不仅能够以多种模式打开文件,还能根据需要创建新文件或打开已有文件进行读写操作。
a. 函数原型
定义:fopen函数的定义是在<stdio.h>头文件中
FILE * fopen ( const char * filename, const char * mode );
filename:这是一个字符串,指明了要打开的文件名。这个名称可以是相对路径或绝对路径。
mode:这也是一个字符串,决定了文件的打开方式。不同的方式决定了对文件的操作类型(读、写或追加)以及是否创建新的文件。
b. 打开模式
"r":只读模式打开文件,如果文件不存在或无法访问则失败。
"w":只写模式打开文件,如果文件已存在则清空内容,不存在则创建新文件。
"a":追加模式,写入的数据将被添加到文件末尾。如果文件不存在,则会创建该文件。
"r+":读写模式,文件必须已经存在。
"w+":可读写模式,如果文件已存在则清空内容,不存在则创建新文件。
"rb" 和 "wb":分别以二进制格式打开文件进行读取和写入。使用二进制模式主要是为了处理非文本数据,如图像或音频文件。
c. 返回值
成功:如果操作成功,fopen函数返回一个FILE指针,该指针指向被打开的文件或流。
失败:如果打开过程中出现错误,如文件不存在或权限不足,fopen函数返回NULL,并设置全局变量errno来指示具体的错误类型。
d. 使用示例
基本使用:一个简单的例子是使用fopen打开一个文件,进行读写操作后,使用fclose关闭文件然后通过各种文件操作函数对该文件进行处理。
错误处理:在实际编程中,检查fopen的返回值是非常重要的,确保文件成功打开后再进行后续操作。
#include <stdio.h>
int main() {
// 打开一个文件
FILE *file = fopen("example.txt", "r");
if (file == NULL) {
printf("无法打开文件
");
return 1;
}
// 执行文件操作,例如读取或写入
// 关闭文件
fclose(file);
return 0;
}
fclose函数是C语言中用于关闭文件的标准函数。此函数主要负责释放由fopen函数打开的文件所占用的资源,确保所有对文件的更改都已保存到磁盘上,并防止数据丢失或资源泄露。
a. 函数原型
定义:fclose函数的定义在<stdio.h>头文件中
int fclose ( FILE * stream );
b. 参数说明
stream:这是一个指向FILE类型的指针,即需要关闭的文件流。这个指针通常来源于之前调用fopen函数时的返回值。
c. 功能描述
关闭文件:fclose关闭由stream指向的文件,释放该文件所占用的所有系统资源,包括文件描述符和内存中的FILE结构。
刷新缓冲区:在文件被关闭之前,所有被缓存的输出操作都会由fclose函数自动刷新到磁盘上,以确保数据的完整性和一致性。
d. 返回值
-成功:如果文件成功关闭,fclose函数返回0。
失败:如果在关闭文件过程中出现错误,则返回EOF,并将全局变量errno设置为具体的错误代码,以供进一步的错误分析。
e. 使用示例
基本使用:一个典型的使用示例如下:首先使用fopen打开文件,完成文件操作后,通过fclose关闭文件。
#include <stdio.h>
int main() {
// 打开一个文件
FILE *file = fopen("example.txt", "r");
if (file == NULL) {
printf("无法打开文件
");
return 1;
}
// 执行文件操作,例如读取或写入
// 关闭文件
fclose(file);
return 0;
}
f. 注意事项
检查返回值:应始终检查fclose的返回值,以确保文件正确关闭。
避免资源泄露:必须关闭所有打开的文件,以防止资源泄露和其他潜在问题。
避免野指针:虽然标准没有要求,但一些安全的编程实践建议在使用fclose后将文件指针设置为NULL,以避免悬挂指针的问题。
(3).文件的读写
C语言中文件的读写操作是程序设计中的基本功能,主要用于数据的永久存储和在不同程序之间的数据交换。文件操作包括读取数据(输入)和写入数据(输出)
A.顺序读写
fgetc函数是C语言中用于读取文件单个字符的函数。此函数从指定的文件流中读取下一个字符,并将文件位置指示器向前移动一位,以便于下一次读取操作。
函数原型
int fgetc ( FILE * stream );
参数说明
stream:这是一个指向FILE类型的指针,即需要从中读取数据的文件流。
#include <stdio.h>
int main() {
// 打开一个文件
FILE *file = fopen("example.txt", "r");
if (file == NULL) {
printf("无法打开文件");
return 1;
}
// 使用fgetc逐个字符地读取文件
int ch;
while ((ch = fgetc(file)) != EOF) {
putchar(ch); // 将读取的字符输出到屏幕上
}
// 关闭文件
fclose(file);
return 0;
}
注意:fgetc函数在读取到文件末尾时会返回EOF(End Of File),这是一个在`stdio.h`中定义的宏,通常具有负值,表示文件结束。
fputc函数是C语言中用于写入单个字符到文件的函数。
函数原型:
int fputc ( int character, FILE * stream );
参数说明:第一个参数`character`是要写入文件的字符,这个字符以整数形式传递给函数。第二个参数`stream`是FILE类型的指针,指向要写入的文件流。这个流可以是之前通过fopen函数打开的任何文件流
#include <stdio.h>
int main() {
// 打开一个文件
FILE *file = fopen("example.txt", "r");
if (file == NULL) {
printf("无法打开文件
");
return 1;
}
// 使用fputc读取字符
fputc('A',file);
// 关闭文件
fclose(file);
return 0;
}
fgets函数是C语言中用于读取文件一行数据的函数。此函数从指定的文件流中读取一行字符,直到遇到换行符、达到指定的最大字符数或到达文件末尾为止
函数原型
char * fgets ( char * str, int num, FILE * stream );
参数说明:在fgets函数的参数中,`str`是一个字符数组,用于存储读取的字符串;`num`是指定的最大读取字符数,包括结束符'\0';`stream`则是要从中读取数据的文件流指针
#include <stdio.h>
int main() {
// 打开一个文件
FILE *file = fopen("example.txt", "r");
if (file == NULL) {
printf("无法打开文件
");
return 1;
}
// 使用fgets读取一行字符串
char line[100];
while (fgets(line, sizeof(line), file) != NULL) {
printf("%s", line); // 将读取的字符串输出到屏幕上
}
// 关闭文件
fclose(file);
return 0;
}
fputs函数是C语言中用于将字符串写入到指定文件流的函数
函数原型:
int fputs ( const char * str, FILE * stream );
参数说明:在fputs函数的参数中,`str`是要写入的字符串,这个字符NULL字符('\0')结束。`stream`是FILE类型的指针,指向要写入的文件流。这个流可以是之前通过fopen函数打开的任何文件流
#include <stdio.h>
int main() {
// 打开一个名为"example.txt"的文件,以写入模式
FILE *file = fopen("example.txt", "w");
if (file != NULL) {
// 调用fputs函数将字符串写入文件
fputs("Hello, World!", file);
// 关闭文件
fclose(file);
}
return 0;
}
fscanf是C语言中的一个标准库函数,用于从指定的文件流中读取格式化输入。
函数原型:
int fscanf ( FILE * stream, const char * format, ... );
参数说明`stream`是指向要读取的文件流的指针,`format`是格式化字符串,后面的省略号表示可变参数列表,用于存储读取到的数据。
#include <stdio.h>
int main() {
// 打开一个名为"example.txt"的文件,以读取模式
FILE *file = fopen("example.txt", "r");
if (file != NULL) {
// 定义变量用于存储读取到的数据
int num;
float fnum;
char ch;
// 调用fscanf函数从文件中读取数据
fscanf(file, "%d %f %c", &num, &fnum, &ch);
// 输出读取到的数据
printf("Read from file: %d, %f, %c", num, fnum, ch);
// 关闭文件
fclose(file);
}
return 0;
}
fprintf是C语言中的一个标准库函数,用于将格式化输出写入到指定的文件流中
函数原型:
int fprintf ( FILE * stream, const char * format, ... );
参数说明:`stream`是指向要写入的文件流的指针,`format`是格式化字符串,后面的省略号表示可变参数列表,用于存储要输出的数据
#include <stdio.h>
int main() {
// 打开一个名为"example.txt"的文件,以写入模式
FILE *file = fopen("example.txt", "w");
if (file != NULL) {
// 调用fprintf函数将格式化数据写入文件
fprintf(file, "The value of pi is approximately %.2f.", 3.14159);
// 关闭文件
fclose(file);
}
return 0;
}
fread是C语言中的一个标准库函数,用于从指定的文件流中读取数据到给定的数组中
函数原型:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
参数说明:`ptr`是一个指向数组的指针,该数组用于存储从文件中读取的数据;`size`是每个数据块的字节数;`count`是要读取的数据块数量;`stream`是指向要读取的文件流的指针
#include <stdio.h>
int main() {
// 打开一个名为"example.bin"的文件,以读取模式
FILE *file = fopen("example.bin", "rb");
if (file != NULL) {
// 定义数组用于存储读取到的数据
char buffer[10];
// 调用fread函数从文件中读取数据
size_t count = fread(buffer, sizeof(char), sizeof(buffer), file);
// 输出读取到的数据
for (size_t i = 0; i < count; i++) {
printf("%c ", buffer[i]);
}
printf("");
// 关闭文件
fclose(file);
}
return 0;
}
使用fread函数可以一次性读取多个数据块,适用于需要从文件中连续读取数据的场景,例如读取二进制文件、图像文件等
fwrite是C语言中的一个标准库函数,用于将数据写入到指定的文件流中
函数原型:
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
参数说明: `ptr`是一个指向要写入的数据的指针;`size`是每个数据块的字节数;`count`是要写入的数据块数量;`stream`是指向要写入的文件流的指针。
#include <stdio.h>
int main() {
// 打开一个名为"example.bin"的文件,以写入模式
FILE *file = fopen("example.bin", "wb");
if (file != NULL) {
// 定义数组用于存储要写入的数据
char buffer[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'};
// 调用fwrite函数将数据写入文件
size_t count = fwrite(buffer, sizeof(char), sizeof(buffer), file);
// 输出实际写入的数据块数量
printf("Written %zu blocks to file.", count);
// 关闭文件
fclose(file);
}
return 0;
}
使用`fwrite`函数可以一次性写入多个数据块,适用于需要向文件中连续写入数据的场景,例如写入二进制文件、图像文件等
B.随机读写
fseek是C语言中的一个标准库函数,用于在文件中定位到指定的位置
函数原型:
int fseek ( FILE * stream, long int offset, int origin );
参数说明:`stream`是指向要定位的文件流的指针;`offset`是要移动的字节数;`origin`是起始位置,可以是以下三个值之一:
SEEK_SET:从文件开头开始计算偏移量 0
SEEK_CUR:从当前位置开始计算偏移量 1
SEEK_END:从文件末尾开始计算偏移量 2
#include <stdio.h>
int main() {
// 打开一个名为"example.txt"的文件,以读写模式
FILE *file = fopen("example.txt", "r+");
if (file != NULL) {
// 将文件指针移动到距离文件开头10个字节的位置
fseek(file, 10, SEEK_SET);
// 读取并输出当前位置的字符
char ch;
ch = fgetc(file);
printf("%c", ch);
// 关闭文件
fclose(file);
}
return 0;
}
ftell是C语言中的一个标准库函数,用于获取文件指针的当前位置
函数原型:
long int ftell ( FILE * stream );
参数说明:`stream`是指向要查询的文件流的指针
#include <stdio.h>
int main() {
// 打开一个名为"example.txt"的文件,以读写模式
FILE *file = fopen("example.txt", "r+");
if (file != NULL) {
// 将文件指针移动到距离文件开头10个字节的位置
fseek(file, 10, SEEK_SET);
// 获取当前位置的偏移量并输出
long int offset = ftell(file);
printf("Current position: %ld", offset);
// 关闭文件
fclose(file);
}
return 0;
}
使用`ftell`函数可以获取文件指针的当前位置,适用于需要知道文件指针位置的场景,例如在文件中进行随机访问、记录文件位置等
rewind是C语言中的一个标准库函数,用于表示将文件指针或数据流的位置重置到起始位置
函数原型:
void rewind ( FILE * stream );
参数说明:`stream`是指向要查询的文件流的指针
#include <stdio.h>
int main() {
FILE *file;
char ch;
// 打开文件
file = fopen("example.txt", "r");
if (file == NULL) {
printf("Failed to open file.");
return -1;
}
// 读取文件内容并输出
while ((ch = fgetc(file)) != EOF) {
putchar(ch);
}
// 倒带
rewind(file);
// 再次读取文件内容并输出
while ((ch = fgetc(file)) != EOF) {
putchar(ch);
}
// 关闭文件
fclose(file);
return 0;
}
使用rewind函数可以将文件指针重新定位到文件的开头,以便重新开始读取或写入文件
4.文件读取结束的判定
文件读取结束的判定是通过检查读取操作的返回值来完成的。在C语言中,文件读取结束可以通过多种方式进行判定,主要依据是读取函数的返回值以及特定状态检测函数的结果
检查函数返回值:大多数文件读取函数如fgetc、fgets和fscanf在达到文件末尾时会返回一个特殊的值。例如,fgetc返回EOF,fgets返回NULL。这些返回值清晰地指示了数据流的末端已经被到达。
feof是C语言中的一个标准库函数,用于检查文件指针是否已经到达文件末尾。
函数原型:
int feof(FILE *stream);
参数说明:`stream`是指向要检查的文件流的指针。
该函数会返回一个非零值,如果文件指针已经到达文件末尾;否则,返回0。
ferror是一个标准库函数,用于检查在文件操作过程中是否发生了错误。
函数原型:
int ferror(FILE *stream);
参数说明:`stream`是指向要检查的文件流的指针。
该函数会返回一个非零值,如果在文件操作过程中发生了错误;否则,返回0。
使用`ferror`函数可以检查在文件操作过程中是否发生了错误,例如在调用`fopen`、`fread`、`fwrite`等函数后,可以使用`ferror`函数来检查是否有错误发生。如果有错误发生,可以使用`clearerr`函数来清除错误标志,或者使用`perror`函数来输出错误信息。
使用feof和ferror函数:虽然直接使用feof函数在读取过程中检测文件末尾并不是推荐的做法,它更多的是用于在读取尝试后判断结束原因是否为到达文件末尾。如果在文件操作后立即检查feof()函数的值,它可以有效地告诉你文件是因为达到了末尾还是因为错误而停止操作。ferror()函数则用来检测是否有读取错误发生,如果有错误发生,该函数返回非零值。