目录
一、什么是文件
二、文件指针的含义
三、文件中常见的可操作函数
1)fopen();讲解
2)fputs();讲解
3)fgets();讲解
4)fflush();讲解
5)fsync();讲解
6)fileno();讲解
7)fclose();讲解
四、示例讲解
1)基础示例
2)进阶示例
五、open();讲解
一、什么是文件
在C语言编程中,文件是指在存储设备上的一个数据集合,可以包含文本、二进制或其他格式的数据。文件可以被打开,读取、写入或关闭。在C语言中,可以使用标准库函数和系统调用函数来操作文件。常见的文件类型包括文本文件和二进制文件,例如文本文件可以包含文本字符串,而二进制文件可以包含任何类型的数据,包括图像、音频、视频等。
二、文件指针的含义
在了解文件中常见的可操作函数之前需了解什么是文件指针,FILE *fp
是一个指向 FILE
类型的指针,用于表示一个打开的文件流。在 C 语言中,文件是通过文件流的方式来进行读写操作的。FILE
类型是一个包含文件状态信息的结构体,用来描述文件的属性,例如文件名、文件类型、读写位置、缓冲区等。
FILE *fp
在程序中的作用是打开并操作一个文件。通过打开文件流,程序可以读取文件内容、写入文件内容、定位文件读写位置、刷新文件流缓冲区等操作。例如,可以使用 fopen()
函数打开一个文件,然后使用 fread()
函数从文件中读取数据,使用 fwrite()
函数向文件中写入数据,使用 fseek()
函数定位文件读写位置,使用 fflush()
函数刷新文件流缓冲区等等。
需要注意的是,打开文件流是一个系统资源开销较大的操作,因此在打开文件流之后,应该尽可能地减少对文件的访问次数,同时在程序退出之前一定要关闭已经打开的文件流,否则可能会造成系统资源浪费或者文件读写错误。
三、文件中常见的可操作函数
1)fopen();讲解
fopen()
是 C 语言中用于打开文件的函数,函数原型如下:
FILE *fopen(const char *filename, const char *mode);
其中,filename
是要打开的文件名,可以是绝对路径或相对路径;mode
是打开文件的模式,可以是以下之一:
模式 | 含义 |
---|---|
“r” | 以只读方式打开文件 |
“w” | 以写入方式打开文件,如果文件不存在则创建新文件 |
“a” | 以追加方式打开文件,如果文件不存在则创建新文件 |
“r+” | 以读写方式打开文件,文件必须存在 |
“w+” | 以读写方式打开文件,如果文件不存在则创建新文件 |
“a+” | 以读写方式打开文件,如果文件不存在则创建新文件,追加数据 |
fopen()
函数返回一个指向 FILE
结构体的指针,该指针可用于后续对文件的读写操作。如果打开文件失败,则函数返回 NULL
。
以下是一个简单的 fopen()
函数示例:
#include int main() {FILE *fp;char buf[1024];// 打开一个名为 example.txt 的文件,以只读方式打开fp = fopen("example.txt", "r");if (fp == NULL) {printf("Failed to open file\n");return 1;}// 从文件中读取一行数据,并输出到控制台fgets(buf, sizeof(buf), fp);printf("%s", buf);// 关闭文件流fclose(fp);return 0;}
2)fputs();讲解
fputs()
是 C 语言中用于向文件写入字符串的函数,函数原型如下:
int fputs(const char *str, FILE *stream);
其中,str
是要写入文件的字符串,stream
是文件流指针。函数将字符串写入到文件流所指向的文件中,直到遇到字符串结束符 \0
。如果写入成功,函数返回非负数;否则返回 EOF
。
需要注意的是,fputs()
函数不会在字符串末尾添加换行符 \n
,因此如果需要在写入的字符串末尾添加换行符,可以手动将其添加到字符串中,或者使用 fprintf()
函数。
以下是一个简单的 fputs()
函数示例:
#include int main() {FILE *fp;// 打开一个名为 example.txt 的文件,以写入方式打开fp = fopen("example.txt", "w");if (fp == NULL) {printf("Failed to open file\n");return 1;}// 向文件中写入一行数据fputs("Hello, World!", fp);// 关闭文件流fclose(fp);return 0;}
3)fgets();讲解
fgets()
是 C 语言中用于从文件中读取一行数据的函数,函数原型如下:
char *fgets(char *str, int size, FILE *stream);
其中,str
是一个字符数组,用于存储读取的数据;size
是 str
的长度,即最多读取的字符数(包括字符串结束符 \0
);stream
是文件流指针,用于指定要读取的文件。
函数将 stream
所指向文件中的一行数据读入 str
,直到遇到文件结束符、换行符 \n
或读取的字符数达到 size-1
为止。如果读取成功,函数返回 str
;否则返回 NULL
。
需要注意的是,fgets()
函数会在读取到换行符时停止读取,并将其包含在字符串中。如果需要去除换行符,可以使用 strtok()
函数或手动将其从字符串中删除。
该函数用法可参考前文。
4)fflush();讲解
fflush()
是 C 标准库中的一个函数,其定义在 头文件中。该函数的作用是将文件流中的数据从缓冲区刷新到物理磁盘上。
在默认情况下,C 标准库会对输出流进行缓冲以提高 IO 性能,这就意味着输出的数据并不是立刻写入磁盘中,而是先存储在缓冲区中,直到满足下列情况之一才会被刷新到磁盘中:
- 缓冲区已满。
- 显式调用
fflush()
函数。 - 文件流被关闭(比如使用
fclose()
函数)。
如果没有显式调用 fflush()
函数或者关闭文件流,缓冲区中的数据可能会因为程序崩溃或者异常退出而丢失。因此,如果数据的完整性对应用程序非常重要,那么需要在写入数据后调用 fflush()
函数,以确保数据已经写入磁盘中。
在读取文件时,如果使用了 fseek()
函数将文件指针移动到新的位置,则需要在读取数据之前显式调用 fflush()
函数以确保文件流的状态正确。
fflush()
函数的原型如下:
int fflush(FILE *stream);
其中,stream
是一个指向文件流的指针,如果该指针为 NULL,则函数将刷新所有的输出流。函数返回值为 0 表示成功,否则表示出错。
5)fsync();讲解
fsync()
是一个 POSIX 标准库函数,其原型定义在 头文件中。该函数的作用是将指定文件描述符(file descriptor)所对应的文件数据从内存写入到磁盘中。
在 Linux 等操作系统中,磁盘 I/O 操作通常是通过缓冲区实现的。缓冲区中的数据需要定期或者在特定情况下刷新到磁盘中以确保数据的一致性和完整性。如果数据还存在于缓冲区中而不是磁盘中,那么在掉电或者系统崩溃等情况下,这些数据可能会丢失。
因此,fsync()
函数通常被用来确保数据已经被写入到磁盘中,以提高数据的可靠性。需要注意的是,fsync()
函数的执行可能会导致一些性能问题,因为它会导致 I/O 操作的阻塞。如果不需要确保数据已经写入磁盘中,那么可以使用 fdatasync()
函数来代替 fsync()
函数,因为后者只会将数据写入到磁盘的数据区域,而不会写入元数据信息。
fsync()
函数的原型如下:
#include int fsync(int fd);
其中,fd
是文件描述符,表示要同步的文件。函数返回值为 0 表示成功,否则表示出错。
6)fileno();讲解
fileno()
是一个 C 标准库函数,其定义在 头文件中。该函数的作用是返回一个流(stream)所对应的文件描述符(file descriptor)。
在 Linux 和类 Unix 系统中,文件描述符是一个非负整数,表示操作系统中打开的文件或者其他 I/O 资源的引用。在 C 标准库中,文件流是一个抽象的概念,它是一个包含缓冲区等状态信息的数据结构,用来表示应用程序与文件之间的交互。
因此,当需要使用 POSIX 标准库或者系统调用操作文件时,就需要将文件流转换为文件描述符。这时候就可以使用 fileno()
函数将文件流转换为文件描述符进行操作。需要注意的是,只有在文件流打开成功后,才能使用 fileno()
函数获得其对应的文件描述符。
fileno()
函数的原型如下:
int fileno(FILE *stream);
其中,stream
是一个指向文件流的指针。如果指针为 NULL,那么函数将返回一个未定义的值。函数返回值是一个文件描述符,表示与指定文件流相关联的文件描述符。
7)fclose();讲解
fclose()
是一个 C 标准库函数,其定义在 头文件中。该函数的作用是关闭一个打开的文件流,并将其与系统中的文件断开连接。在关闭文件流之前,该函数会先刷新文件流中的缓冲区,以确保所有数据都已经写入到磁盘中。
在 Linux 和类 Unix 系统中,文件是操作系统中打开的一个或多个文件描述符的抽象。在 C 标准库中,文件流是一个包含缓冲区等状态信息的数据结构,用来表示应用程序与文件之间的交互。
因此,当需要关闭文件并将其与系统中的文件断开连接时,就可以使用 fclose()
函数。需要注意的是,当一个文件流关闭之后,就不能再对其进行读写操作。
fclose()
函数的原型如下:
int fclose(FILE *stream);
其中,stream
是一个指向文件流的指针,指向需要关闭的文件流。如果文件流已经被关闭,那么函数将返回 EOF(-1)。如果关闭成功,函数将返回 0。如果在关闭文件时发生了错误,函数将返回一个非零值。
四、示例讲解
前文了解了一堆常见的文件操作函数,下面举一些示例进行分析:
1)基础示例
下面是一个简单的 C 语言程序示例,演示如何使用 fflush()
、fsync()
、fileno()
和 fclose()
函数。
#include #include #include int main() {FILE *fp;char buf[] = "Hello, world!\n";fp = fopen("example.txt", "w");if (fp == NULL) {perror("Failed to open file");exit(EXIT_FAILURE);}// 将数据写入文件流中fputs(buf, fp);// 刷新文件流中的缓冲区fflush(fp);// 获取文件描述符并强制将缓冲区中的数据写入磁盘fsync(fileno(fp));// 关闭文件流并断开与文件的连接fclose(fp);return 0;}
该程序会将字符串 "Hello, world!\n"
写入名为 example.txt
的文件中,并使用 fflush()
函数将缓冲区中的数据写入文件流中。接着,程序使用 fileno()
函数获取文件流的文件描述符,并使用 fsync()
函数将缓冲区中的数据强制写入磁盘。最后,程序使用 fclose()
函数关闭文件流并断开与文件的连接。
2)进阶示例
以下是一个示例程序,演示如何使用 fopen()
、fputs()
、fgets()
、fflush()
、fsync()
、fileno()
和 fclose()
函数对文件进行读写和同步操作:
#include #include #include #include #include #include #include int main() {FILE *fp;int fd;char buf[1024];const char *filename = "example.txt";const char *text = "Hello, World!";// 打开一个名为 example.txt 的文件,以写入方式打开fp = fopen(filename, "w");if (fp == NULL) {printf("Failed to open file\n");return 1;}// 将字符串写入文件fputs(text, fp);// 刷新文件缓冲区并将数据写入磁盘fflush(fp);fsync(fileno(fp));// 关闭文件流fclose(fp);// 打开刚才写入的文件,以只读方式打开fp = fopen(filename, "r");if (fp == NULL) {printf("Failed to open file\n");return 1;}// 读取文件中的一行数据,并输出到控制台fgets(buf, sizeof(buf), fp);printf("DEBUG :%s(%d)-: %s\n",__FILE__, __LINE__, __FUNCTION__,buf);//输出当前语句所在的文件名__FILE__、行数__LINE__、函数__FUNCTION__、输出数据buf// 关闭文件流fclose(fp);// 获取文件描述符fd = open(filename, O_WRONLY);if (fd < 0) {printf("Failed to open file\n");return 1;}// 将字符串写入文件write(fd, text, strlen(text));// 刷新文件缓冲区并将数据写入磁盘fsync(fd);// 关闭文件描述符close(fd);// 打开刚才写入的文件,以只读方式打开fp = fopen(filename, "r");if (fp == NULL) {printf("Failed to open file\n");return 1;}// 读取文件中的一行数据,并输出到控制台fgets(buf, sizeof(buf), fp);printf("DEBUG :%s(%d)-: %s\n",__FILE__, __LINE__, __FUNCTION__,buf);//输出当前语句所在的文件名__FILE__、行数__LINE__、函数__FUNCTION__、输出数据buf// 关闭文件流fclose(fp);#if 1 /*控制是否删除文件*/// 删除文件if (remove(filename) != 0) {printf("Failed to delete file\n");return 1;}#endifreturn 0;}
该程序首先打开一个名为 example.txt
的文件,以写入方式打开,将字符串 “Hello, World!” 写入文件中,然后刷新文件缓冲区并将数据写入磁盘,并关闭文件流。接下来,程序再次打开该文件,以只读方式打开,从文件中读取一行数据,并输出到控制台。然后,程序通过获取文件描述符的方式,将字符串 “Hello, World!” 写入文件中,刷新文件缓冲区并将数据写入磁盘,并关闭文件描述符。接着,程序再次打开该文件,以只读方式打开,从文件中读取一行数据,并输出到控制台。
可参考以下文章(附带C语言在线编译工具—将上述代码进行编译)
谭浩强C语言程序设计(1-3章代码学习)—-该文章附带C语言在线编译工具
编译结果如下:
五、open();讲解
上述示例中包含open();函数,open()
函数是 POSIX 系统下的一个系统调用,用于打开或创建一个文件,并返回一个文件描述符。函数原型如下:
#include #include #include int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode);
其中,pathname
参数是要打开或创建的文件路径名;flags
参数是一个标志位,用于指定打开方式和访问权限;mode
参数用于指定新文件的访问权限,仅在创建新文件时有效。
open()
函数返回一个非负整数的文件描述符,如果出现错误,则返回 -1。
flags
参数可选值如下:
O_RDONLY
:以只读方式打开文件。O_WRONLY
:以只写方式打开文件。O_RDWR
:以读写方式打开文件。O_APPEND
:在文件末尾追加写入数据。O_CREAT
:如果文件不存在,则创建一个新文件。O_EXCL
:与O_CREAT
一起使用,如果文件已经存在,则返回错误。O_TRUNC
:如果文件已经存在,截断文件长度为零。
mode
参数可选值如下:
S_IRWXU
:用户(文件所有者)具有读、写和执行权限。S_IRUSR
:用户具有读权限。S_IWUSR
:用户具有写权限。S_IXUSR
:用户具有执行权限。S_IRWXG
:用户组具有读、写和执行权限。S_IRGRP
:用户组具有读权限。S_IWGRP
:用户组具有写权限。S_IXGRP
:用户组具有执行权限。S_IRWXO
:其他用户具有读、写和执行权限。S_IROTH
:其他用户具有读权限。S_IWOTH
:其他用户具有写权限。S_IXOTH
:其他用户具有执行权限。
以下是一个 open()
函数的示例:
#include #include #include #include int main() {int fd;char buf[1024];const char *filename = "example.txt";const char *text = "Hello, World!";// 打开一个名为 example.txt 的文件,以只写方式打开fd = open(filename, O_WRONLY);if (fd < 0) {printf("Failed to open file\n");return 1;}// 将字符串写入文件write(fd, text, strlen(text));// 关闭文件描述符close(fd);// 打开刚才写入的文件,以只读方式打开fd = open(filename, O_RDONLY);if (fd < 0) {printf("Failed to open file\n");return 1;}// 读取文件中的一行数据,并输出到控制台read(fd, buf, sizeof(buf));printf("%s", buf);// 关闭文件描述符close(fd);return 0;}
该程序以只写方式打开名为 example.txt
的文件,如果文件不存在则创建文件,然后将字符串 “Hello, World!” 写入文件中,最后关闭文件描述符。
笔记分享,如有误,感谢指教;