流动的代码:文件流畅读写的艺术(二)文件顺序读写函数

简介:

文件的顺序读写

fgetc 与 fputs

fgetc 函数用于从指定的文件流中读取下一个字符。如果成功,它返回读取到的字符;如果到达文件末尾或发生读取错误,它则返回 EOF


简单示例:


#include 
int main() {
    FILE *file = fopen("example.txt", "r");
    if (file) {
        int ch;
        while ((ch = fgetc(file)) != EOF) {
            putchar(ch);  // 将字符输出到标准输出
        }
        fclose(file);
    }
    return 0;
}


现在有一个test1.txt文件,我写入abcde,让fgetc读,并打印到屏幕上:

这里就是光标逐次往后移动。


fputc 函数用于向指定的文件流中写入一个字符


int fputc(int char, FILE *stream);


char 是要写入的字符。虽然参数类型是 int,但只会使用该 int 值的低 8 位(即一个字符)。

stream 是指向 FILE 对象的指针,代表要写入字符的文件流。通常,这个 FILE 对象是通过 fopen 函数获得的。

示例


#define _CRT_SECURE_NO_WARNINGS 1
#include 
int main()
{
  FILE* pf = fopen("test1.txt", "w");
  if (pf == NULL)
  {
  perror("fopen");
  return -1;
  }
  fputc('a', pf);
  fputc('b', pf);
  fputc('c', pf);
  fputc('d', pf);
  fclose(pf);
  pf = NULL;
  return 0;
}


当然也可以用标准输出流打印到屏幕上

现在让我们做一个练习、

将test1.txt中的内容拷贝一份,生成test2.txt文件


从test1.txt中读取数据,写到test2.txt中。


首先,打开两个文件,分别进行读和写:


FILE* pfread = fopen("test1.txt", "r");
if (pfread == NULL)
{
  perror("fopen->test1.txt");
  return -1;
}
FILE* pfwrite = fopen("test2.txt", "w");
if (pfwrite == NULL)
{
  fclose(pfread);
  perror("fopen->test2.txt");
  return -1;
}

若第二个文件没有打开成功,则需要关闭第一个文件.


接着进行数据的读写


我们用fgetc读取,若读取不成功返回-1(EOF),那么我们可以使用while语句


int ch = 0;
while ((ch = fgetc(pfread)) != EOF)
{
  fputc(ch, pfwrite);
}


再讲返回的值写到test2.txt中

完整代码如下:


#include 
int main()
{
  FILE* pfread = fopen("test1.txt", "r");
  if (pfread == NULL)
  {
  perror("fopen->test1.txt");
  return -1;
  }
  FILE* pfwrite = fopen("test2.txt", "w");
  if (pfwrite == NULL)
  {
  fclose(pfread);
  perror("fopen->test2.txt");
  return -1;
  }
  int ch = 0;
  while ((ch = fgetc(pfread)) != EOF)
  {
  fputc(ch, pfwrite);
  }
  fclose(pfread);
  fclose(pfwrite);
  pfread = NULL;
  pfwrite = NULL;
  return 0;
}

fgets和fputs

fgets用于从文件流中读取字符串,其原型如下:


char *fgets(char *str, int num, FILE *stream);


char *str: 指向用于接收读取到的数据的字符数组的指针

int num: 指定最多要读取的字符数量(包括最后的 null 终止符 \0)

FILE *stream: 指定要读取的文件流。

fgets 函数会从指定的文件流 stream 中读取字符,直到发生以下几种情况之一:


读取了 num - 1 个字符。

遇到换行符 \n,换行符也会被读取并存入字符串中。

遇到文件结束符(EOF)。

在任何情况下,fgets 都会在字符串末尾加上 null 终止符 \0 来确保字符串的正确终止。

这里我们可以通过观察代码来理解:

在test1.txt中放入abcdefgh,定义一个字符数组来读取:


int main()
{
  FILE* pf=fopen("test1.txt", "r");
  if (pf == NULL)
  {
  return 1;
  }
  char arr[20] = "xxxxxxxxxxxxxxxx";
  fgets(arr, 7, stdin);
  fclose(pf);
  pf = NULL;
  return 0;
}


fgets最多读取6个字符,最后补充一个/0;

调试如下:


如果函数执行成功,则返回 str(指向字符串的指针)。如果读取失败或遇到文件结束符且没有读取任何字符,则返回 NULL。


举例如下:


1. int main() {
2.     FILE* file;
3.     char buffer[100];
4. 
5.     // 打开文件
6.     file = fopen("test1.txt", "r");
7.     if (file == NULL) {
8.         perror("fopen");
9.         return -1;
10.     }
11. 
12.     // 使用fgets从文件中读取一行
13.     if (fgets(buffer, 100, file) != NULL) {
14.         printf("读取的字符串: %s\n", buffer);
15.     }
16.     else {
17.         printf("读取失败或文件已结束\n");
18.     }
19. 
20.     // 关闭文件
21.     fclose(file);
22. 
23.     return 0;
24. }

我们test1.txt中仍放入abcde;

buffer用于接收

运行结果如下:

fputs用于向文件流中写入一个字符串,其原型如下:


int fputs(const char *str, FILE *stream);


const char *str:指向包含了你希望写入文件的以 null 结尾的字符串的指针

fputs 函数将字符串 str 写入到指定的文件流 stream 中,字符串的 null 终止符不写入到文件流。成功时,函数返回非负值;失败时,返回 EOF

需要注意的是,fputs 函数不会为你自动添加换行符 \n,如果需要新的一行开始,则你需要显式地在字符串中包含 \n。

现在我们再进行演示,将test1.txt文件写入test2.txt中

首先,打开两个文件:


char buffer[100];
 // 打开文件
 FILE* firead= fopen("test1.txt", "r");
 FILE* fiwrite= fopen("test2.txt", "w");
 if (firead == NULL) {
     perror("fopen->test.txt");
     return -1;
 }
 if (fiwrite == NULL) {
     perror("fopen->test2.txt");
     return -1;
 }

再进行读写:


while (fgets(buffer, 100, firead) != NULL) {
    if (fputs(buffer, fiwrite) != EOF)
    {
        printf("写入成功");
    }
    else
        printf("失败");
}
// 关闭文件
fclose(firead);
fclose(fiwrite);
return 0;

当然,也可以用stdin,和stdout进行标准输入和输出


fprintf和fscanf

讲fprintf之前,先提一下printf函数

printf:


int printf(const char *format, ...);


const char *format:格式字符串,用于指定输出的格式。

“…”:可变参数列表,提供了与格式字符串中的格式指定符相对应的输出值。

例如打印一个数字:

printf("%d",num);


而fprintf函数,它的原型如下:


int fprintf(FILE *stream, const char *format, ...);


与printf不同的是它多了一个流;

fprintf 会根据提供的格式字符串,将数据格式化后写入指定的文件流。它在成功写入时返回写入的字符数,失败时返回负值。

对比


输出目标:fprintf 用于向文件写入数据,而 printf 用于向**标准输出(如终端或控制台)**写入数据。

第一个参数:fprintf 需要一个额外的 FILE 参数*来指定输出的文件,而 printf 直接将输出发送到标准输出。

用途:fprintf 更适用于文件操作,如日志记录、数据保存等;printf 主要用于与用户的交互、程序的调试信息输出等。

例如:


FILE *file = fopen("output.txt", "w");
if (file != NULL) {
    fprintf(file, "The number is: %d\n", 42);
    fclose(file);
}


打开一个output.txt的文件,写入The number is: a这部分内容


fscanf

fscanf 函数从文件流读取格式化输入


int fscanf(FILE *stream, const char *format, ...);


fscanf 会尝试按照指定的格式从文件流中读取数据,并将读取的数据存储在提供的地址上。成功时,它返回成功匹配并赋值的数据项数量****(读取成功n个则返回n)。如果到达文件末尾或发生读取错误,它返回 EOF


同样对比scanf函数:

int scanf(const char *format, ...);


scanf 与 fscanf 非常相似,唯一的区别是 scanf 读取标准输入(如用户在键盘上的输入),而不是从一个文件流读取。它同样返回成功匹配并赋值的数据项数量,或者在遇到输入错误时返回 EOF。

对比


数据来源:最主要的区别是 fscanf 从文件或指定的输入流读取,而 scanf 从**标准输入(如键盘)**读取。

用途:fscanf 常用于读取文件中的数据,而 scanf 常用于从用户手动输入中读取数据。

第一个参数:fscanf 需要一个额外的 FILE 参数*来指定输入流,而 scanf 默认从标准输入读取数据。

假设从写好的output文件中读取


int main() {
    FILE* file = fopen("output.txt", "r"); // 打开文件用于读取
    int a;
    if (file != NULL) {
        // 使用fscanf读取文件中的整数
        if (fscanf(file, "The number is: %d\n", &a) == 1) {
            fprintf(stdout,"读取的整数是:%d\n", a);
        }
        else {
            fprintf(stdout,"读取失败\n");
        }
        fclose(file); // 关闭文件
    }
    else {
        perror("打开文件失败");
        return 1;
    }
    return 0;
}

stdout为标准输出,打印到屏幕上;

fread和fwirte

与上面六种函数不同的是,上述函数均为文本类或字符类输入输出,而fread和fwrite函数用于二进制的输入和输出。

fwrite

fwrite 函数用于向文件中写入数据,它的函数原型:


size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);


const void *ptr 是指向要写入的数据的指针。

size_t size 是每个数据项大小(字节为单位)。

size_t nmemb 是要写入的数据项的个数。

举例:现在将数字1000写入我的output.txt文件中:


1. int main() {
2.     FILE *file;
3.     int number = 1000;
4. 
5.     // 打开文件用于二进制写入
6.     file = fopen("output.txt", "wb");
7.     if (file == NULL) {
8.         perror("Error opening file");
9.         return 1;
10.     }
11. 
12.     // 使用fwrite写入二进制数
13.     fwrite(&number, sizeof(int), 1, file);
14. 
15.     // 关闭文件
16.     fclose(file);
17. 
18.     return 0;
19. }


我们会发现它的内容是不可读的

我们再用fread读取.

fread


size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);


我们会发现两个函数参数相同,无非就是一个读,一个写;

那么用fread读取刚刚的output.txt文件:


#include 
int main() {
    FILE *file;
    int number;
    // 打开文件用于二进制读取
    file = fopen("output.txt", "rb");
    if (file == NULL) {
        perror("Error opening file");
        return 1;
    }
    // 使用fread读取二进制数
    size_t itemsRead = fread(&number, sizeof(int), 1, file);
    if (itemsRead == 1) {
        printf("读取的整数是:%d\n", number);
    } else {
        // 如果没有读取到一个整数,打印错误信息
        if (feof(file)) {
            printf("文件结束,未读取到数据。\n");
        }
        if (ferror(file)) {
            printf("读取文件时出错。\n");
        }
    }
    // 关闭文件
    fclose(file);
    return 0;
}



本篇文章到此结束,后期为大家补充剩余的内容!感谢观看


相关文章
|
弹性计算 缓存 负载均衡
ECS通知问题之频繁告警如何解决
ECS(Elastic Compute Service,弹性计算服务)是云计算服务提供商提供的一种基础云服务,允许用户在云端获取和配置虚拟服务器。以下是ECS服务使用中的一些常见问题及其解答的合集:
|
4天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
8340 37
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
3天前
|
缓存 测试技术 API
Qwen 3.7 Plus 与 Max 实测:性价比与多模态能力差异解析(2026)
2026 年 6 月 1 日,阿里悄无声息地发布了 Qwen 3.7 Plus,距 Qwen 3.7 Max 上线刚好 11 天。同样的 1M 上下文,同样的 35 小时自治上限。但价格才是头条:Plus 是 0.40/M输入,Max是 2.50/M——便宜约 6 倍——并且还能看图、看视频。Vision Arena 上 Plus 已经排到 #16。所以这周真正值得讨论的问题不是”要不要为视觉能力买单”,而是”Max 凭什么用 6 倍价格换来 2 个百分点的 benchmark 领先”。
|
4天前
|
JavaScript 定位技术 API
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
CodeGraph 是一款爆火的本地代码智能工具,通过 tree-sitter 解析 AST 构建结构化知识图谱(存于 SQLite),为编程 Agent 提前生成“代码地图”。它显著降低 Agent 在中大型项目中的探索成本——实测工具调用减少71%、Token 降57%、速度提升46%,支持19+语言及主流框架路由识别,完全离线、无需 API Key。
557 3
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
|
4天前
|
人工智能 运维 JavaScript
阿里云Qoder CN(原通义灵码)全解析 产品形态、版本划分与技术适配说明
在AI辅助开发与智能办公工具持续普及的当下,阿里云旗下原通义灵码正式更名为Qoder CN,同时延伸出QoderWork CN、Qoder CN CLI、Qoder CN Mobile等多款配套产品,形成覆盖代码开发、日常办公、终端交互、移动端使用的完整工具矩阵。Qoder CN核心定位为AI智能编码助手,深度适配主流代码编辑器、集成开发环境以及终端场景;QoderWork CN则偏向桌面端综合办公辅助,二者面向不同使用场景,划分了多个版本档位,搭配差异化资源配额、功能权限与计费规则,同时兼容多款主流大模型。
580 4
|
4天前
|
数据采集 人工智能 前端开发
让 Coding Agent 从黑盒到透明:阿里云 Agent 观测审计数据采集实践
AI Agent 规模化落地带来执行黑盒、行为难追溯、成本难度量三大难题。阿里云基于 OTel 标准,面向 Coding Agent、个人通用助理和框架型 Agent,推出 LoongSuite Pilot、插件及探针等无侵入采集方案,让 Agent 实现可看见、可分析、可审计、可治理。
704 148
|
4天前
|
人工智能 缓存 自然语言处理
阿里Qwen3.7-Max评测:Agent能力显著提升,耗时与调用成本大幅下降
阿里云百炼推出面向智能体的旗舰大模型Qwen3.7-Max,具备长周期自主执行能力,显著提升编程、办公自动化等复杂任务处理水平;支持MCP集成与多框架兼容,并以限时5折+100万Tokens免费试用大幅降低使用门槛,助力企业高效落地AI应用。在阿里云百炼平台快速体验:https://t.aliyun.com/U/fPVHqY
1931 10
|
4天前
|
存储 安全 Java
AgentScope Java 2.0:打造分布式、企业级智能体底座
AgentScope 2.0 面向分布式部署、稳定运行、权限安全等企业级需求全面升级,打造支持多租户隔离与长期稳定运行的企业级智能体底座。
|
4天前
|
人工智能 运维 API
2026年阿里云百炼通义千问Qwen3.7-plus深度介绍 功能特性、使用优势及618大促订阅方案指南
大模型技术的普及,让AI能力逐步融入个人办公、内容创作、代码编写、企业运营、教育培训等各类场景。不同定位的模型对应不同使用需求,旗舰级模型性能强劲但使用成本偏高,轻量化模型价格低廉却难以胜任复杂任务,而介于两者之间的中端主力模型,凭借均衡的能力、亲民的定价、广泛的场景适配性,成为绝大多数个人用户、小型团队、中小企业的首选。
720 1
|
4天前
|
人工智能 安全 定位技术
CodeGraph深度解析 让Claude Code工具调用直降七成的核心原理与实操教程
如今以Claude Code为代表的AI编程智能体已经成为开发者日常编码、项目重构、漏洞修复的必备工具。但在长期使用过程中,几乎所有开发者都会遇到同一个明显痛点:AI虽然具备强大的代码生成与分析能力,却常常陷入盲目探索的循环中。
1333 2