news 2026/2/16 18:19:10

标准IO之文件读写

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
标准IO之文件读写
  • 流支持不同的读写方式
    • 读写一个字符:fgetc()/fputc()
    • 读写一行:fgets()和fputs()
    • 读写若干个对象:fread()/fwrite(), 每次读/写若干个对象,而每个对象具有相同的长度

字符读写

字符输入

  • 用来输入一个字符
  • 头文件:
    • #include <stdio.h>

函数原型

  • int fgetc(FILE *stream);
    • 从流中读取下一个字符,并将其作为unsigned char强制转换为int类型返回,若到文件末尾或出错时返回EOF(-1)
  • int getc(FILE *stream);//宏
    • 等价于fgetc(),不同之处是它可以作为一个宏来实现,对stream进行多次求值
    • getc和fgetc区别是一个是宏一个是函数
  • int getchar(void);
    • 成功时返回读取的字符;若到文件末尾或出错时返回EOF(-1)
    • getchar 等同于fgetc(stdin)
    • stdin 也是FILE *的指针,是系统定义好的,指向的是标准输入(键盘输入)
    • 调用getchar会阻塞,等待你的键盘输入

函数返回值是int类型不是char类型,主要是为了扩展返回值的范围

打开文件后读取,是从文件开头开始读,a+a+读完一个后读写指针会后移

#include<stdio.h>intmain(intargc,constchar*argv[]){intc;FILE*fp=NULL;if((fp=fopen("test.txt","r+"))==NULL){perror("fopen\n");return-1;}printf("fopen success\n");while(1){#if0if((c=fgetc(fp))==EOF){perror("fgetc");break;}#elseif((c=getc(fp))==EOF){perror("getc");break;}#endifprintf("%c",(char)c);}fclose(fp);return0;}

字符输出

  • 头文件:
    • #include <stdio.h>

函数原型

  • int fputc(int c, FILE *stream);
    • 将字符c(强制转换为无符号字符)写入流
  • int putc(int c, FILE *stream);//宏
    • 等价于fputc(),不同之处是它可以作为宏来实现,对stream进行多次求值
  • int putchar(int c);
    • 成功时返回写入的字符,出错时返回EOF
    • putchar©等同于fputc(c, stdout)
  • fputc()、putc()和putchar()返回作为无符号字符写入的字符,在错误时返回EOF

以上函数返回和输入参数都是int类型

遇到这种错误:Bad file descriptor, 很可能是文件打开的模式错误(只读模式去写,只写模式去读),或文件的读写权限不能满足文件打开设置的需求

#include<stdio.h>intmain(intargc,constchar*argv[]){intc;FILE*fp=NULL;if((fp=fopen("test.txt","a+"))==NULL){perror("fopen\n");return-1;}printf("fopen success\n");#if1if((c=fputc('a',fp))==EOF){perror("fputc");return-1;}#elif0if((c=putc('a',fp))==EOF){perror("putc");return-1;}#elseputchar('b');#endifprintf("c = %c\n",c);fclose(fp);return0;}

例程:字符读写复制文件

#include<stdio.h>intmain(intargc,constchar*argv[]){FILE*fp_a=NULL,*fp_b=NULL;intc=0;if(argc<3){printf("Usage: %s <be copied file> <copied file>\n",argv[0]);return-1;}if((fp_a=fopen(argv[1],"r+"))==NULL){perror("be copied file fopen");return-1;}if((fp_b=fopen(argv[2],"w+"))==NULL){perror("copied file fopen");fclose(fp_a);return-1;}printf("fopen files ok\n");do{if((c=fgetc(fp_a))==EOF){perror("fgetc");break;}if(fputc(c,fp_b)==EOF){perror("fputc");break;}}while(1);fclose(fp_a);fclose(fp_b);return0;}

行输入输出

行输入

  • 头文件:
    • #inculde <stdio.h>

函数原型

  • char *gets(char *s);
    • 读取标准输入到缓冲区s

注意这个函数是危险的,不检查缓冲区溢出,永远不要使用gets()

gets()从stdin读取一行到s所指向的缓冲区,直到一个结束换行符或EOF,它用空字节(‘\0’)替换。因为在事先不知道数据的情况下不可能知道gets()将读取多少字符,并且因为gets()将继续存储超过缓冲区末尾的字符,所以使用它是非常危险的。它可能被用来破坏计算机安全,使用fgets()代替。

  • char *fgets(char *s, int size, FILE *stream);
    • 输入的数据超出size,size-1个字符会保存到缓冲区,最后添加’\0’,
    • 输入数据少于size-1,后面会添加’\n’和’\0’
  • 返回值:
    • 成功时返回s,到文件末尾或出错时返回NULL
  • 读取文件内容
#include<stdio.h>#defineN32#defineM6intmain(intargc,constchar*argv[]){FILE*fp=NULL;charbuf[M]={0};if((fp=fopen("test.txt","r+"))==NULL){perror("fopen");return-1;}while(1){if(fgets(buf,M,fp)==NULL){perror("fgets");break;}printf("test look:%s",buf);}printf("fgets from file ok\n");fclose(fp);return0;}

行输出

  • 头文件:
    • #include <stdio.h>
  • 函数原型:
    • int puts(const char *s);
    • int fputs(const char *s, FILE *stream);
  • 返回值:
    • 成功时返回非负整数(输出字符个数)
    • 出错时返回EOF(-1)
  • 参数:
    • puts将缓冲区s中的字符串输出到stdout,并追加’\n’
    • fputs将缓冲区s中的字符串输出到stream,不追加’\n’
#include<stdio.h>#defineN32intmain(intargc,constchar*argv[]){FILE*fp=NULL;charbuf[N]={0};if((fp=fopen("test.txt","a+"))==NULL){perror("fopen");return-1;}if(fgets(buf,N,stdin)==NULL){perror("fgets");fclose(fp);return-1;}if(fputs(buf,fp)==EOF){perror("fputs");fclose(fp);return-1;}printf("fputs ok\n");fclose(fp);return0;}

例程:统计文件行数

  • 如何统计一个文本文件包含多少行?
#include<stdio.h>#include<string.h>#defineN32intmain(intargc,constchar*argv[]){FILE*fp=NULL;intcout=0;charbuf[N]={0};if((fp=fopen("test.txt","a+"))==NULL){perror("fopen");return-1;}while(1){if(fgets(buf,N,fp)==NULL){perror("fgets");break;}if(buf[strlen(buf)-1]=='\n'){cout++;}}printf("cout=%d\n",cout);fclose(fp);return0;}

二进制、对象读写

  • 文本文件:每一个字符都是一个字节,外存存储对应ASCII码值。对于数值,以字符形式在外存上存储对应ASCII值。文本流中的数据可以显示和打印出来,都是用户可以读懂的信息
  • 二进制文件:流中的数据是按照二进制编码的方式(值的方式)来存放文件。二进制数据也可在屏幕上显示, 但其内容无法读懂
  • fread、fwrite既可以读写文本文件,也可以读写数据文件;

fread 读

  • 头文件:
    • #include <stdio.h>
  • 函数原型:
    • size_t fread(void *ptr, size_t size, size_t n, FILE *fp);
  • 参数:
    • void *ptr读内容要放的位置的指针
    • size_t size读取的"块"大小
    • size_t n每次函数运行读取的"块"个数
    • FILE *fp要读取文件的文件指针
  • 返回值:
    • 成功返回读写的对象个数
    • 出错时返回EOF
#include<stdio.h>#defineN10intmain(intargc,constchar*argv[]){FILE*fp=NULL;charbuf[N]={0};size_tret=-1;if((fp=fopen(argv[1],"r+"))<0){perror("fread");return-1;}ret=fread(buf,sizeof(buf),1,fp);if(0>ret){perror("fread");fclose(fp);return-1;}printf("test buf=%s",buf);fclose(fp);return0;}

fwrite 写

  • 头文件:
    • #include <stdio.h>
  • 函数原型:
    • size_t fwrite(const void *ptr, size_t size, size_t n, FILE *fp);
  • 参数:
    • void *ptr 要写的内容的位置指针
    • size_t size 写的一个"块"大小
    • size_t n 每次函数运行写的"块"个数
    • FILE *fp 要写入文件的文件指针
  • 返回值:
    • 成功返回读写的对象个数
    • 出错时返回EOF
#include<stdio.h>#include<unistd.h>typedefstructnote{intid;charname[8];floatscore;}STU;intmain(intargc,constchar*argv[]){FILE*fp=NULL;if((fp=fopen("test.txt","a+"))<0){perror("perror");return-1;}STU s[2]={{1,"wang",98},{2,"li",95}};intlen=sizeof(STU);if(fwrite(&s[0],len,1,fp)<0){perror("fwrite");fclose(fp);return-1;}fflush(fp);sleep(5);if(fwrite(&s[1],len,1,fp)<0){perror("fwrite");fclose(fp);return-1;}sleep(5);fclose(fp);if((fp=fopen("test.txt","r+"))<0){perror("perror");return-1;}STU ret;fread(&ret,len,1,fp);printf("%d,%s,%f\n",ret.id,ret.name,ret.score);fclose(fp);return0;}

文件写完后,文件指针指向文件末尾,如果这时候去读,读不出来内容的

例程:读写复制文件

  • 如何利用 fread / fwrite 实现文件的复制?
#include<stdio.h>#include<string.h>#defineN512intmain(intargc,constchar*argv[]){FILE*fp_r=NULL,*fp_w=NULL;if(argc<3){printf("Usage: %s <source file> <destination file>\n",argv[0]);return-1;}if((fp_r=fopen(argv[1],"r"))==NULL){printf("fopen source file failed\n");return-1;}if((fp_w=fopen(argv[2],"a+"))==NULL){printf("fopen destination file failed\n");return-1;}charbuf[N]={0};size_tbytes_read,bytes_write;while(1){// 判断文件流指针是不是已经移动到文件末尾if(feof(fp_r)){printf("read file in last line\n");break;}if((bytes_read=fread(buf,1,sizeof(buf),fp_r))<0){printf("fread failed\n");gotoEND;}if((bytes_write=fwrite(buf,1,bytes_read,fp_w))<0){printf("fwrite failed\n");gotoEND;}// 如果写入的数据量不等于读取的数据量,则表示写入失败if(bytes_read!=bytes_write){printf("failed to write to destination file\n");gotoEND;}bzero(buf,sizeof(buf));}printf("file copied successfully form '%s' to '%s'\n",argv[1],argv[2]);END:fclose(fp_r);fclose(fp_w);return0;}
  • 字符数组使用后,空间不会自己清空,不影响下次使用需要主动清。bzero函数可以给指定的空间上都填充ASCII值0,表示清空
#include<strings.h>voidbzero(void*s,size_tn);
  • feof函数可以判断文件是否读到末尾(文件读写指针),检查stream 指向的流的文件结束指示符,如果已达到,则返回非零值
#include<stdio.h>intfeof(FILE*stream);

格式化输入输出

格式化输入

  • int fscanf(FILE *stream, const char *format, ...);
    • 从文件流读取格式化输入
  • int sscanf(const char *str, const char *format, ...);
    • 从字符串读取格式化输入
  • int scanf(const char *format, ...);
    • 标准输入版本(实际是fscanf的特殊形式)
    • 等价于 fscanf(stdin, format, …)
  • 成功时返回输出的字符个数,出错时返回EOF

格式化输出

  • int fprintf(FILE *stream, const char *fmt, …);
    • 格式化输出到文件流
  • int sprintf(char *s, const char *fmt, …);
    • 格式化输出到字符串
  • int printf(const char *format, ...);
    • 标准输出版本
    • 等价于 fprintf(stdout, format, …)
  • 成功时返回输出的字符个数,出错时返回EOF
#include<stdio.h>intmain(intargc,constchar*argv[]){charbuf[32]={0};#if0FILE*fp=NULL;if((fp=fopen(argv[1],"a+"))==NULL){perror("fopen");return-1;}fprintf(fp,"%s","hello");fscanf(stdin,"%s",buf);fprintf(fp,"%s",buf);fclose(fp);#endifinta,b,c;sscanf("1 2","%d %d %d",&a,&b,&c);sprintf(buf,"a=%d,b=%d,c=%d\n",a,b,c);printf("%s\n",buf);return0;}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/16 13:47:04

【Open-AutoGLM云电脑效率革命】:7天掌握视频编解码优化核心技术

第一章&#xff1a;Open-AutoGLM云电脑视频效率革命全景解读Open-AutoGLM作为新一代云原生智能推理框架&#xff0c;正深刻重塑云端视频处理的工作范式。其核心在于将大语言模型与图形流水线深度融合&#xff0c;实现从指令理解到视频渲染的端到端自动化&#xff0c;显著提升内…

作者头像 李华
网站建设 2026/2/15 11:21:15

Qwen1.5本地部署终极指南:新手10分钟搭建专属AI助手

Qwen1.5本地部署终极指南&#xff1a;新手10分钟搭建专属AI助手 【免费下载链接】Qwen1.5 项目地址: https://gitcode.com/GitHub_Trending/qw/Qwen1.5 想要在本地快速部署强大的Qwen1.5大语言模型吗&#xff1f;这篇指南将带你从零开始&#xff0c;用最简单的方式完成…

作者头像 李华
网站建设 2026/2/4 5:40:34

7大技术突破:DeepSeek-V3.2-Exp-Base如何重塑企业AI推理成本结构

当前企业AI部署面临的核心矛盾&#xff1a;算力成本指数级增长与推理精度线性提升不成正比。传统大模型在处理复杂任务时需激活全部参数&#xff0c;单次推理成本动辄数百美元&#xff0c;这让众多企业在AI应用落地时望而却步。深度求索最新开源的推理模型DeepSeek-V3.2-Exp-Ba…

作者头像 李华
网站建设 2026/2/10 13:39:55

AI模型训练不断线:智能断点恢复完整指南

AI模型训练不断线&#xff1a;智能断点恢复完整指南 【免费下载链接】ai-toolkit Various AI scripts. Mostly Stable Diffusion stuff. 项目地址: https://gitcode.com/GitHub_Trending/ai/ai-toolkit 还在为AI模型训练意外中断而烦恼吗&#xff1f;AI-Toolkit的强大训…

作者头像 李华
网站建设 2026/2/7 23:23:20

3步实战:彻底解决FSDP模型保存内存爆炸的终极方案

3步实战&#xff1a;彻底解决FSDP模型保存内存爆炸的终极方案 【免费下载链接】verl verl: Volcano Engine Reinforcement Learning for LLMs 项目地址: https://gitcode.com/GitHub_Trending/ve/verl 你遇到过这种情况吗&#xff1f;训练了几个小时的大模型&#xff0c…

作者头像 李华
网站建设 2026/2/10 12:38:15

轻量级AI革命:Gemma 3 270M如何重新定义移动智能边界

轻量级AI革命&#xff1a;Gemma 3 270M如何重新定义移动智能边界 【免费下载链接】gemma-3-270m-it-qat-GGUF 项目地址: https://ai.gitcode.com/hf_mirrors/unsloth/gemma-3-270m-it-qat-GGUF 想象一下&#xff0c;你正在地铁上需要快速翻译一份外文文档&#xff0c;但…

作者头像 李华