C语言——文件操作

简介: 本文介绍了文件的基本操作,包括文件的打开、关闭、读取和写入。使用`fopen`函数以不同模式(如“r”、“w”等)打开文件,并通过`fclose`关闭。文章详细解释了如何利用`fputc`、`fputs`及`fprintf`进行格式化写入,同时介绍了`fgetc`、`fgets`和`fscanf`用于文件内容的读取。此外,还涵盖了二进制文件的读写方法以及如何通过`fseek`、`ftell`和`rewind`实现文件的随机访问。

文件的打开和关闭

我们用下面两个函数实现文件的打开和关闭

对于fopen来说,第一个参数传入一个文件的名字,第二个为打开的方式,返回值为一个文件指针,如果打开失败就返会NULL
fclose里的参数为传入一个文件指针

我们来看具体的例子

int main() {
    FILE* pf = fopen("text.txt", "r");//用pf来接收
    if (pf == NULL) {
        perror("fopen");
        return 1;
    }
    //关闭文件,指针置为空
    fclose(pf);
    pf = NULL;
    return 0;
}

上面我们是以"r"的方式打开一个文件名为"text.txt"的文本文件,那么下面我们来介绍一下打开方式


我们上面的代码中是采取了 “r” 的方式打开文件,但是在此之前项目文件夹里并没有目标文件,所以打开文件失败,运行报错

文件的读写

文件的写入

接下来我们来了解一下文件的读写函数

我们先来认识一下fgetc()函数,首先第一个参数需要传入一个字符,第二个参数为目标流

int main() {
    FILE* pf = fopen("text.txt", "w");//选用w的方式打开文件
    if (pf == NULL) {
        perror("fopen");
        return 1;
    }
    fputc('a', pf);
    fputc('\n', pf);
    for (char c = 'a'; c <= 'z'; c++) {
        fputc(c, pf);
    }
    //关闭文件,指针置为空
    fclose(pf);
    pf = NULL;
    return 0;
}

当采用w的方式打开文件后,自动创建了一个"text.txt"文件,之后调用了fputc函数向文件中写入字符

这样一个字符一个字符的写入有点麻烦,还可以通过fputs()函数实现写入一个字符串

fputs("hello word",pf);

也就是把写入文件的代码换成上面的
格式化写入
如果需要指定写入的格式的话就用到了 fprintf()函数

下面是具体使用方法

struct person {
    char name[20];
    int age;
};
int main() {
    struct person p = { "zhangsan",20 };
    FILE* pf = fopen("text.txt", "w");
    if (pf == NULL) {
        perror("fopen");
        return 1;
    }
    //格式化写入
    fprintf(pf, "%s %d", p.name, p.age);
    fclose(pf);
    pf = NULL;
    return 0;
}

可以看出,fprintf的参数类型只比printf多了一个流

文件的读取

接下来介绍一下fgetc()函数,如果读取成功,返回的是字符的ASCII码值,如果读取到文件末尾或者读取失败,返回EOF(-1)

int main() {
    //FILE* pf = fopen("text.txt", "w");
    FILE* pf = fopen("text.txt", "r");
    if (pf == NULL) {
        perror("fopen");
        return 1;
    }
    /*for (char c = 'a'; c <= 'z'; c++) {
        fputc(c, pf);
    }*/
    char a1 = fgetc(pf);
    printf("%c\n", a1);
    char  a2= fgetc(pf);
    printf("%c\n", a2);
    //关闭文件,指针置为空
    fclose(pf);
    pf = NULL;
    return 0;
}

在以w的方式打开之后写入字符,再以r的方式打开读取字符,讲函数返回值接受并以字符形式打印,读取是按照顺序依次往下读取,根据读取到文件末尾返回值为EOF,可以用一个循环来实现对文件中所有字符进行遍历。

同理,也可以一次读取一个字符串,使用的函数就是与之对应的fgets()
** fgets()的使用 **
fgets需要传入三个参数,第一个是接受字符串的指针,第二个是读取的字节数,第三个是读取的流,读取成功的话返回字符串的指针,读取失败或者读取到文件末尾,返回NULL

char arr[10] = {0};
fgets(arr,10,pf);
printf("%s",arr);

有一点需要注意的是,虽然是读取10个字节,但是第10个位置要预留给’\n’

格式化读取
与fprintf对应的就是fscanf,使用方法也与scanf类似

struct person {
    char name[20];
    int age;
};
int main() {
    struct person p = { "zhangsan",20 };
    FILE* pf = fopen("text.txt", "r");
    if (pf == NULL) {
        perror("fopen");
        return 1;
    }
    //格式化写入
    //fprintf(pf, "%s %d", p.name, p.age);
    //格式化读取
    fscanf(pf, "%s %d", p.name, &(p.age));
    printf("%s %d\n", p.name, p.age);
    fclose(pf);
    pf = NULL;
    return 0;
}

二进制文件的写入和读取

int main() {
    int arr[] = { 1,2,3,4,5 };
    FILE* pf = fopen("text.txt", "wb");//二进制形式打开
    if (pf == NULL) {
        perror("fopen");
        return 1;
    }
    int sz = sizeof(arr) / sizeof(arr[0]);
    //以二进制形式写入
    fwrite(arr, sizeof(arr[0]), sz, pf); 
    // 参数依次为写入的目标指针,每个元素大小(字节),写入元素个数,写入流的形式
    fclose(pf);
    pf = NULL;
    return 0;
}

由于是以二进制形式写入,所以文本形式下看不出来写入的内容,需要以二进制形式读取

int main() {
    int arr[] = { 1,2,3,4,5 };
    FILE* pf = fopen("text.txt", "rb");//二进制形式打开
    if (pf == NULL) {
        perror("fopen");
        return 1;
    }
    int sz = sizeof(arr) / sizeof(arr[0]);
    //读取二进制文本
    fread(arr, sizeof(arr[0]), 1, pf);
    // 参数依次为写入的目标指针,每个元素大小(字节),一次读取个数,写入流的形式
    printf("%d", arr[0]);
    fclose(pf);
    pf = NULL;
    return 0;
}

文件的随机读取

上面的文件操作函数都是按照顺序进行读取,接下来介绍一下随机读取的函数

int main() {
    FILE* pf = fopen("text.txt", "r");
    if (pf == NULL) {
        perror("fopen");
        return 1;
    }
    char c = fgetc(pf);
    printf("%c\n", c);
    fseek(pf, 3, SEEK_CUR);//光标从当前位置偏移量为3
    c = fgetc(pf);
    printf("%c\n", c);
    fclose(pf);
    pf = NULL;
    return 0;
}

当text.txt文件中为abcdefg时运行结果

结合这些操作就可以实现访问任意元素
ftell()
ftell函数返回的是文件指针相对于起始位置的偏移量

printf("%d",ftell(pf));

函数只有一个参数,返回值为偏移量
rewind()
rewind函数的作用就是返回到文件的起始位置

rewind(pf);
相关文章
|
4天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
1天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2158 11
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
1天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1161 13
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
1月前
|
运维 Cloud Native Devops
一线实战:运维人少,我们从 0 到 1 实践 DevOps 和云原生
上海经证科技有限公司为有效推进软件项目管理和开发工作,选择了阿里云云效作为 DevOps 解决方案。通过云效,实现了从 0 开始,到现在近百个微服务、数百条流水线与应用交付的全面覆盖,有效支撑了敏捷开发流程。
19265 29
|
1月前
|
人工智能 自然语言处理 搜索推荐
阿里云Elasticsearch AI搜索实践
本文介绍了阿里云 Elasticsearch 在AI 搜索方面的技术实践与探索。
18805 20
|
1月前
|
Rust Apache 对象存储
Apache Paimon V0.9最新进展
Apache Paimon V0.9 版本即将发布,此版本带来了多项新特性并解决了关键挑战。Paimon自2022年从Flink社区诞生以来迅速成长,已成为Apache顶级项目,并广泛应用于阿里集团内外的多家企业。
17509 13
Apache Paimon V0.9最新进展
|
1月前
|
存储 人工智能 前端开发
AI 网关零代码解决 AI 幻觉问题
本文主要介绍了 AI Agent 的背景,概念,探讨了 AI Agent 网关插件的使用方法,效果以及实现原理。
18695 16
|
1月前
|
人工智能 自然语言处理 搜索推荐
评测:AI客服接入钉钉与微信的对比分析
【8月更文第22天】随着人工智能技术的发展,越来越多的企业开始尝试将AI客服集成到自己的业务流程中。本文将基于《10分钟构建AI客服并应用到网站、钉钉或微信中》的解决方案,详细评测AI客服在钉钉和微信中的接入流程及实际应用效果,并结合个人体验分享一些心得。
9914 9
|
3天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
|
2天前
|
缓存 前端开发 JavaScript
终极 Nginx 配置指南(全网最详细)
本文详细介绍了Nginx配置文件`nginx.conf`的基本结构及其优化方法。首先通过删除注释简化了原始配置,使其更易理解。接着,文章将`nginx.conf`分为全局块、events块和http块三部分进行详细解析,帮助读者更好地掌握其功能与配置。此外,还介绍了如何通过简单修改实现网站上线,并提供了Nginx的优化技巧,包括解决前端History模式下的404问题、配置反向代理、开启gzip压缩、设置维护页面、在同一IP上部署多个网站以及实现动静分离等。最后,附上了Nginx的基础命令,如安装、启动、重启和关闭等操作,方便读者实践应用。
149 77
终极 Nginx 配置指南(全网最详细)