C语言:文件操作

embedded/2024/9/24 0:18:35/

为什么使用文件

在之前的通讯录程序中,我们介绍了如何使用文件来实现数据的持久化。然而,我们只是创建了储存功能,但只限于程序运行时。在程序退出以后,数据就不存在了。为了解决这个问题,我们通常会将数据存储到磁盘文件或数据库中。
使用文件我们可以将数据存放到电脑硬盘上,做到数据持久化

什么是文件

文件是指在磁盘或其他存储媒体上存储数据的一种数据结构。在程序设计中有两种文件:程序文件和数据文件。

程序文件

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

数据文件

文件的内容不一定是程序,而是程序运行时读写的数据。

文件名

文件名包括了三个部分:文件路径+文件名主干+文件后缀
eg:c:\code\test.txt#

文件的打开和关闭

文件指针

缓冲文件系统中关键概念是文件类型指针,简称文件指针。
每次被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件名,文件状态和文件的当前位置),这些信息保存在一个结构体变量中,该结构体变量由系统声明,取名:FILE。
在不同的编译环境下,FILE包含的内容大同小异。
每打开一个文件,系统会根据文件情况自动创建一个FILE,并填充其中信息
对一个程序员来说,一般通过FILE的指针来维护FILE结构变量。
在这里插入图片描述

文件的打开和关闭

文件在读写前应先打开文件,结束后应关闭文件。
在编写程序时,打开文件时会返回一个FILE的指针指向改文件,建立了指针与文件的关系。
ANIC规定用
fopen打开文件fclose*关闭文件

fopen

FILE * fopen(const charfilename,const char mode)

filename:这是一个字符串,包含了您想要打开的文件的路径。这个路径可以是相对路径或绝对路径。

相对路径:相对路径(Relative Path)是相对于当前工作目录(或者当前文件的位置)的路径。它不包含从根目录(如 Unix 系统中的 /,Windows 系统中的 C:\)开始的全部信息,而是从当前目录开始到目标文件或目录的路径。

例如,如果您的当前工作目录是 /home/user/documents,那么相对路径 subfolder/file.txt 指的是 /home/user/documents/subfolder/file.txt。
绝对路径:绝对路径(Absolute Path)是一个完整的文件系统路径,它从文件系统的根目录开始,指定了文件或目录在文件系统中的确切位置。无论当前工作目录在哪里,绝对路径都能正确地定位到目标文件或目录。
mode:fopen 函数可以使用多种模式来打开文件。下面是所有有效的模式字符串列表:

“r”: 打开文件用于读取。如果文件不存在,fopen 返回 NULL。
“w”: 打开文件用于写入。如果文件存在,则清空内容;如果文件不存在,则创建新文件。
“a”: 打开文件用于追加。如果文件存在,数据将被追加到文件末尾;如果文件不存在,则创建新文件。
“r+”: 打开文件用于读写。如果文件不存在,fopen 返回 NULL。
“w+”: 打开文件用于读写。如果文件存在,则清空内容;如果文件不存在,则创建新文件。
“a+”: 打开文件用于读取和追加。如果文件存在,数据将被追加到文件末尾;如果文件不存在,则创建新文件。
“rb”: 打开二进制文件用于读取。
“wb”: 打开二进制文件用于写入。
“ab”: 打开二进制文件用于追加。
“rb+”: 打开二进制文件用于读写。
“wb+”: 打开二进制文件用于读写。
“ab+”: 打开二进制文件用于读取和追加。
此外,还可以在模式字符串中包含以下特殊字符:

“t”: 文本模式(默认值)。
“b”: 二进制模式。
“+”: 同时进行读写操作。

eg:
FILE* pf=fopen(“data.txt”,“r”);
尝试打开名为 data.txt 的文件,以便进行读取操作。如果文件存在且打开成功,fopen 函数将返回一个指向 FILE 对象的指针,该指针可以用来 subsequent I/O 操作。如果文件不存在或者由于其他原因无法打开,fopen 函数将返回 NULL。

fclose

int fclose(FILE *stream);
参数说明:

stream: 这是一个 FILE 类型的指针,它指向之前通过 fopen 函数打开的文件。
函数返回值:

如果关闭成功,fclose 函数返回 0。
如果发生错误,fclose 函数返回 EOF(-1 的宏定义)。
功能说明:

当您完成文件的读写操作后,应该使用 fclose 函数来关闭文件。这不仅会释放文件描述符和相关资源,还会确保所有的缓冲区内容都被刷新到文件中,从而确保数据的持久保存。

文件的顺序读写

函数名称作用原型返回值说明
fgetc从文件中读取一个字符int fgetc(FILE *stream);读取的字符或 EOF每次调用读取文件的一个字符
fputc将一个字符写入文件int fputc(int c, FILE *stream);写入的字符或 EOF每次调用写入文件的一个字符
fgets从文件中读取一行文本char *fgets(char *str, int n, FILE *stream);读取的文本或 NULL每次调用读取文件的一行文本
fputs将一行文本写入文件int fputs(const char *str, FILE *stream);写入的字节数或 EOF每次调用写入文件的一行文本
fscanf读取文件并转换成变量int fscanf(FILE *stream, const char *format, ...);读取并转换的输入项数根据格式字符串读取文件并转换成变量
fprintf将变量格式化后写入文件int fprintf(FILE *stream, const char *format, ...);写入的字节数根据格式字符串将变量写入文件
fread从文件中读取数据size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);读取的字节数或 EOF每次调用读取指定数量的字节
fwrite将数据写入文件size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);写入的字节数每次调用写入指定数量的字节
eg 1: 使用 fgetc 读取文件中的一个字符
#include <stdio.h>
int main() {FILE *fp;char ch;fp = fopen("data.txt", "r"); // 打开文件用于读取if (fp == NULL) {perror("Error opening file");return -1;}ch = fgetc(fp); // 读取文件中的第一个字符printf("Read character: %c\n", ch);fclose(fp); // 关闭文件return 0;
}

eg 2: 使用 fgets 读取文件中的一行文本

#include <stdio.h>
int main() {FILE *fp;char buffer[100];fp = fopen("data.txt", "r"); // 打开文件用于读取if (fp == NULL) {perror("Error opening file");return -1;}fgets(buffer, 100, fp); // 读取文件中的一行文本printf("Read line: %s\n", buffer);fclose(fp); // 关闭文件return 0;
}

eg 3: 使用 fwrite 写入数据到文件

#include <stdio.h>
int main() {FILE *fp;int data[] = {1, 2, 3, 4, 5};size_t bytes_written;fp = fopen("data.bin", "wb"); // 打开文件用于写入if (fp == NULL) {perror("Error opening file");return -1;}bytes_written = fwrite(data, sizeof(int), 5, fp); // 写入数据到文件printf("Written bytes: %zu\n", bytes_written);fclose(fp); // 关闭文件return 0;
}

每个例子都包含了打开文件、执行读写操作和关闭文件的步骤。这些例子展示了如何在 C 语言中使用这些基本的文件操作函数。

文件的随机读写

文件的随机读写是指可以读取或写入文件中的任意位置的数据,而不必按照文件的顺序进行。随机读写函数允许你直接跳转到文件中的特定位置,读取或写入一个或多个字节。以下是一些常用的文件随机读写函数。
在 C 语言中,文件的随机读写是指可以读取或写入文件中的任意位置的数据,而不必按照文件的顺序进行。随机读写函数允许你直接跳转到文件中的特定位置,读取或写入一个或多个字节。以下是一些常用的文件随机读写函数:

文件随机读取函数

  1. fseek
    int fseek(FILE *stream, long int offset, int whence);
    
    fseek 函数用于设置文件的读/写位置。stream 参数是指向 FILE 对象的指针,offset 是一个长整型数,表示从 whence 指定的位置开始的偏移量。whence 参数可以是 SEEK_SET(文件开头)、SEEK_CUR(当前位置)或 SEEK_END(文件末尾)。函数返回 0 表示成功,或者返回 -1 表示失败。
  2. ftell
    long int ftell(FILE *stream);
    
    ftell 函数用于获取当前文件的读/写位置。函数返回当前位置相对于文件开头的偏移量,如果出错,返回 -1
  3. fgetc(用于随机读取)
    int fgetc(FILE *stream);
    
    fgetc 函数用于读取文件的一个字符。为了实现随机读取,你首先需要使用 fseek 函数将文件指针移动到想要读取的位置。

文件随机写入函数

  1. fputc(用于随机写入)
    int fputc(int c, FILE *stream);
    
    fputc 函数用于写入文件的一个字符。为了实现随机写入,你首先需要使用 fseek 函数将文件指针移动到想要写入的位置。
  2. fwrite
    size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
    
    fwrite 函数用于向文件中写入数据。为了实现随机写入,你首先需要使用 fseek 函数将文件指针移动到想要写入的位置。

示例代码

以下是一个简单的示例,展示了如何使用 fseekfwrite 函数进行文件的随机写入:

#include <stdio.h>
int main() {FILE *fp;int data[] = {1, 2, 3, 4, 5};size_t bytes_written;fp = fopen("data.bin", "w+b"); // 打开文件用于写入和读取if (fp == NULL) {perror("Error opening file");return -1;}// 将文件指针移动到文件末尾fseek(fp, 0, SEEK_END);// 写入数据到文件末尾bytes_written = fwrite(data, sizeof(int), 5, fp);printf("Written bytes: %zu\n", bytes_written);// 关闭文件fclose(fp);return 0;
}

在上面的示例中,我们使用了 fseek 函数将文件指针移动到文件末尾,然后使用 fwrite 函数向文件末尾写入数据。这样可以实现文件的随机写入操作。

rewind 函数

用于将文件指针重新定位到文件的开始位置。这个函数非常有用,当你想要从头开始重新读取一个文件时,而不想从头开始逐字节移动文件指针。以下是 rewind 函数的原型:

void rewind(FILE *stream);

rewind 函数接受一个指向 FILE 对象的指针 stream,表示要重置的文件流。调用 rewind 函数后,文件指针将移动到文件的开头,就像文件刚刚被打开一样。
下面是一个使用 rewind 函数的示例:

#include <stdio.h>
int main() {FILE *fp;int ch;fp = fopen("data.txt", "r"); // 打开文件用于读取if (fp == NULL) {perror("Error opening file");return -1;}// 读取文件的一个字符ch = fgetc(fp);printf("Read character: %c\n", ch);// 将文件指针重新定位到文件开始位置rewind(fp);// 重新读取文件的一个字符ch = fgetc(fp);printf("Rewinded and read character: %c\n", ch);// 关闭文件fclose(fp);return 0;
}

在上述示例中,我们首先读取了文件 data.txt 的一个字符,然后调用了 rewind 函数将文件指针重新定位到文件的开头。之后,我们再次读取了文件的一个字符。由于 rewind 函数的作用,第二次读取的是文件开头的同一个字符。
rewind 函数通常用于数据处理任务,比如当你需要对文件进行多次读取操作,并且每次都需要从文件开始处读取时,使用 rewind 函数可以简化代码,避免手动移动文件指针的复杂性。

文件读取结束的判定

在 C 语言中,文件操作是编程中的一个常见任务。当我们读取文件时,我们需要一种方法来确定何时我们已经到达文件的末尾。这里,我们要讨论的是如何使用 feof 函数来帮助我们判断文件是否已经读取完毕。
首先,我们需要明确一点:feof 函数并不直接告诉我们文件是否结束,而是告诉我们文件指针是否已经到达文件末尾。这意味着,即使 feof 返回 1,文件也可能还有数据,只是文件指针已经超出了数据区域。因此,我们不能仅仅依赖 feof 的返回值来判断文件是否结束。
正确的方法是,在每次读取操作之后,检查读取函数的返回值。例如,当我们使用 fgetcfgets 读取文件时,如果文件已经读取完毕,fgetc 会返回 EOF(End Of File),而 fgets 会返回一个空字符串(\0)。这样,我们就可以确定文件是否已经读取完毕。
下面是一个示例,展示了如何正确使用 fgetcfeof

#include <stdio.h>
int main() {FILE *fp;int ch;fp = fopen("data.txt", "r"); // 打开文件用于读取if (fp == NULL) {perror("Error opening file");return -1;}// 逐字符读取文件while ((ch = fgetc(fp)) != EOF) {printf("Read character: %c\n", ch);}// 检查是否到达文件末尾if (feof(fp)) {printf("Reached end of file due to EOF.\n");} else {printf("Did not reach end of file.\n");}// 关闭文件fclose(fp);return 0;
}

在这个示例中,我们使用 while 循环逐字符读取文件。每次 fgetc 函数读取一个字符后,我们检查返回值是否为 EOF。如果是,我们使用 feof 函数来确认是否已经到达文件末尾。如果 feof 返回 1,我们输出 “Reached end of file due to EOF.”;如果返回 0,我们输出 “Did not reach end of file.”。
这样,我们就通过正确的逻辑来判断文件是否读取结束,而不是直接依赖 feof 的返回值。这种方法可以确保我们在文件末尾正确地处理数据,而不会错误地认为文件中还有未读取的数据。


http://www.ppmy.cn/embedded/7771.html

相关文章

Windows系统安装SeaFile个人云盘服务器并实现公网访问管理文件

文章目录 1. 前言2. SeaFile云盘设置2.1 Owncould的安装环境设置2.2 SeaFile下载安装2.3 SeaFile的配置 3. cpolar内网穿透3.1 Cpolar下载安装3.2 Cpolar的注册3.3 Cpolar云端设置3.4 Cpolar本地设置 4.公网访问测试5.结语 1. 前言 现在我们身边的只能设备越来越多&#xff0c…

vue3+elementui-plus实现无限递归菜单

效果图 实现方式是&#xff1a;通过给定的数据结构层数来动态生成多级菜单 menu.vue<template><el-menu:default-active"activeIndex"class"el-menu-demo"mode"horizontal"select"handleSelect"background-color"#f8f…

搜索+剪枝,LeetCode 216. 组合总和 III

目录 一、题目 1、题目描述 2、接口描述 python3 cpp 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 python3 cpp 一、题目 1、题目描述 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多…

Jmeter-非GUI模式下运行jmeter脚本-适用于服务器上持续集成测试

背景 大部分Jmeter脚本都是部署在Linux上运行&#xff0c;利用Jenkins做接口自动化&#xff0c;定时巡检任务。 执行命令 1.进入jmeter的目录&#xff0c;bin文件夹 cd C:\path\to\jmeter\bin2.运行脚本文件 jmeter -n -t D:\{脚本文件目录}\xxx.jmx -l D:\{脚本文件目录}…

Springboot的Test单元测试操作

Springboot的Test单元测试操作 简单总结需要操作的步骤 1&#xff0c;导入依赖 2&#xff0c;创建目录&#xff08;目录和启动类的目录保持一致&#xff09; 3&#xff0c;添加注解 4&#xff0c;写方法测试 1&#xff0c;导入依赖 <dependency><groupId>org.spri…

OpenStack 常见模块详解

目录 一、OpenStack 架构 二、控制台 Dashboard 三、身份认证服务 Keystone 1&#xff09;用户&#xff08;user&#xff09; 2&#xff09;项目&#xff08;project&#xff09; 3&#xff09;角色&#xff08;role&#xff09; 4&#xff09;服务&#xff08;serv…

C语言语法进阶

条件运算符 条件运算符是 C 语言中唯一的一种三目运算符。三目运算符代表有三个操作数&#xff1b;双目 运算符代表有两个操作数&#xff0c;如逻辑与运算符就是双目运算符&#xff1b;单目运算符代表有一个操作数&#xff0c; 如逻辑非运算符就是单目运算符。运算符也称操作符…

react之组件与JSX

第一章 - 描述用户界面 概述&#xff1a;React是一个用于构建用户界面&#xff08;UI&#xff09;的JavaScript库&#xff0c;用户界面由按钮&#xff0c;文本和图像等小单元内容构建而成。React帮助你把它们组合成可重用&#xff0c;可嵌套的组件。从web端网站到移动端应用&a…