翁老师说现在很少有人直接用C语言来操作文件来储存或者读取数据了,稍微有点量的用数据库。个人觉得C语言实现文件操作还是挺有意思的。做个练习——一个简单的学生信息系统

头文件

#ifndef _STUDENT_H_
#define _STUDENT_H_#define STR_SIZE 20
/*声明学生结构体*/
typedef struct _student{int id;char name[STR_SIZE];int gender;int age;
}STUDENT;
#endifvoid getlist(STUDENT *std,int num);//读入学生信息
int save(STUDENT *std,int num);//储存至文件
void read(FILE *fp,int cnt);//读取数据 

main函数,确定学生数量,调用getlist(),用数组存储(也可用链表);调用save(),将数据保存至文件;调用read(),读取数据。

#include <stdio.h>
#include <stdlib.h>
#include "student.h"int main(int argc, char *argv[]) {int num=0;printf("请输入学生数量:");scanf("%d",&num);STUDENT std[num];//学生结构数组 getlist(std,num);//读取数据,也就是给给各元素的成员赋值 printf("是否保存数据?(1-保存,0-取消)");int flag=-1;scanf("%d",&flag);if(flag){if(save(std,num)){printf("保存成功\n");}else{printf("保存失败\n");}}/*读取*/FILE *fp=fopen("student.date","r");if(fp){
//fseek()函数可将文件指针指向某位置,SEEK_SET-文件头,SEEK_END-文件末,SEEK_CUR-文件当前位置,第二个参数是偏移字节数,+-决定偏移方向       fseek(fp,0,SEEK_END);
//ftell()函数,定位文件指针位置,返回文件头到该位置的字节数int num=ftell(fp)/sizeof(STUDENT);printf("共有%d个数据,要看第几个?",num);int cnt;scanf("%d",&cnt); read(fp,cnt);fclose(fp);}return 0;
}

分别用二进制模式和文本模式写入、读取文件

void getlist(STUDENT *std,int num){char format[STR_SIZE];sprintf(format,"%%%ds",STR_SIZE-1); //利用格式化输出,做一个格式字符串“%19s” for(int i=0;i<num;i++){printf("请输入第%d个学生的信息\n\t学号:",i+1);scanf("%d",&std[i].id);printf("\n\t姓名:");scanf(format,std[i].name);//格式字符串的地址替代“%s”printf("\n\t性别(0-女,1-男):");scanf("%d",&std[i].gender);printf("\n\t年龄:");scanf("%d",&std[i].age);}
}
int save(STUDENT *std,int num){int ret=0;FILE *fp=fopen("student.date","w");if(fp){ret=fwrite(std,sizeof(STUDENT),num,fp);//二进制写入文件
//文本写入文件
//      for(int i=0;i<num;i++){
//          fprintf(fp,"学号:%d",std[i].id);
//          fprintf(fp,"\n姓名:%s",std[i].name);
//          fprintf(fp,"\n性别:%s",(std[i].gender==1?"男":"女"));
//          fprintf(fp,"\n年龄:%d",std[i].age);
//          fprintf(fp,"\n");
//      }
//      ret=1;//文本模式下赋值1,代表执行到此,写入成功 fclose(fp);}else{printf("文件打开失败!");}
//  return ret;return ret==num;//二进制写入文件fwrite()返回值为写入 某个结构体(某大小字节块) 的个数
}
/*读取文件内数据*/
void read(FILE *fp,int cnt){
//以文本模式读取文件内容,一次读入100个字符,fgets遇行末‘\0’停止、遇到换行停止。
//  char s[100];
//  while(fgets(s,100,fp)){
//      printf("%s\n",s);
//  }
//以二进制模式读取文件内容,可用fseek()函数定位至第几个结构。 STUDENT std;fseek(fp,(cnt-1)*sizeof(STUDENT),SEEK_SET);fread(&std,sizeof(STUDENT),1,fp);printf("学号:%d\n",std.id);printf("姓名:%s\n",std.name);printf("性别:%s\n",std.gender==1?"男":"女"); printf("年龄:%d\n",std.age);
}

注意:r+和w+的读写模式,在第一次读取或者写入后,文件指针会指向读取或者写入的当前位置,无法继续进行反向操作。只有rewind()重置指针位置至文件头才能继续。

w和w+会清空原文件内容;

a和a+是在文件末追加内容,不会清空原文件内容;

r+会覆盖原文件内容。

补充知识点,格式化输入输出:

一、格式化输出

printf("%d",i)中,%d为格式化输出字符串在%和d中间可以添加4种参数:

%[flag][width][.prec][hil]type

1、flag

flag 含义
- 左对齐
+ 显示+-符号
空格 正数留空
0 0填充所占位数

例:

#include <stdio.h>
#include <stdlib.h>
int main(int argc,char const *argv[]){int a=50,b=-100;printf("|%-+9.5d|\n|%+-9.4d|\n",a,b);system("pause");return 0;
}

2、width和.prec

width/.prec 含义
number 输出所占字符数
.number

对于float保留几位小数

对于int是填补0后共占用几个字符数

* 将number作为参数替代字符串中的*
.* 将.number作为参数替代字符串中的.*

例:

#include <stdio.h>
#include <stdlib.h>
int main(int argc,char const *argv[]){float a=50,b=-100;printf("|%-+*.*f|\n|%+-*.*f|\n",9,6,a,9,5,b);system("pause");return 0;
}

由此可得当[width]和[.prec]冲突时,以[.prec]为主,width自动增加。

3、HIL

类型修饰(HIL) 含义
hh 以单字节形式输出
h short
l long
ll long long
L long double

hh以单字节形式输出:例如一个整形占4个字节,hh将最小字节上的内容输出。

例:12345 二进制最小字节内容为0011 1001,则输出为57。

但:我的电脑hhd单字节格式输出不正常, 不知道什么原因。。。

当printf("%hhd",(char)a);输出单字节整数时,对a进行强制类型转换,输出57正确。

#include <stdio.h>
#include <stdlib.h>int main(int argc,char const *argv[]){int a=12345;printf("%i\n",a);//a可以是8/10/16进制的任何一种 printf("%u\n",a);//unsigned 无符号整形 printf("%o\n",a);//八进制整形 printf("%x\n",a);//十六进制整形 printf("%hhd\n",(char)a);//单字节整形 unsigned int mask=1;for(mask=1u<<31;mask;mask>>=1){//二进制printf("%d",a&mask?1:0); }return 0;
}

#include <stdio.h>
#include <stdlib.h>int main(int argc,char const *argv[]){int a=54321;printf("%hhi\n",a);//a可以是8/10/16进制的任何一种 printf("%hhu\n",a);//unsigned 无符号整形 printf("%#o\n",a);//八进制整形 #可以显示8和16进制的前缀 printf("%#x\n",a);//十六进制整形 printf("%hhd\n",(char)a);//单字节整形 unsigned int mask=1;for(mask=1u<<31;mask;mask>>=1){//二进制 printf("%d",a&mask?1:0); }return 0;
}

4、利用格式化输出可以自己制作格式化输出字符串。

例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define len 20
int main(int argc,char const *argv[]){float a=50,b=-100;char format[len];sprintf(format,"%%%ds",len-1);//自定义一个格式化字符串"%19s"输出到format里面.printf("%s\n",format);char name[len];scanf(format,name);printf("%s\n",name);return 0;
}

二、格式化输入

scanf("%d",&a);

%[flag]type

flag 含义 flag 含义
* 跳过 l long
number 输入最大字符数 ll long long
hh char L double long
h short
type 含义 type 含义
d int a/e/f/g float
i 可8可10可16 c char
u unsigned int s 字符串
o 8进制 p 指针
x 16进制 [^。] 。前的所有字符

*跳过输入指定格式;i的输入格式可为10、8、16三种进制

例:

#include <stdio.h>
#include <stdlib.h>int main(int argc,char const *argv[]){int num;scanf("%*d%i",&num);printf("%d",num);return 0;
}

#include <stdio.h>
#include <stdlib.h>
#define len 20
int main(int argc,char const *argv[]){char str[len];scanf("%*[^.].%[^.].",str);
//%*[^.].跳过.前面所有字符并读掉.;%[^.].读取.前面的所有字符放入str,并读掉.printf("%s",str);return 0;
}

三、scanf和printf的返回值

scanf返回值为整形,返回读取的变量个数。

printf返回值为整形,返回输出的字符个数。

#include <stdio.h>
#include <stdlib.h>
#define len 20
int main(int argc,char const *argv[]){char str[len];int a=scanf("%*[^.].%[^.].",str);int b=printf("%s\n",str);printf("a:b=%d:%d",a,b);return 0;
}

a为读取的变量个数,在程序中第一个字段跳过,第二个字段存入了str也就是读取了一个字符数组。b为输出的字符个数,在程序中输出了str,也就是san以及\n换行共4个字符。

四、其他输入输出方式

C语言除了scanf和printf外,还有getchar和putchar用于读取和输出单个字符;gets和puts用于读取和输出字符串;fgets和fputs也是用来读取和输出字符串;fscanf和fprintf用来和文件交互,读取或者输入。用法如下:

1、int c=getchar(void)读入单个字符,存为int型;int num=putchar(c),输出单个字符,返回该字符的int型值。

2、char *str=gets(char *str);读入字符串,存入str.该函数遇到换行符结束读取,会将换行符读掉,并在字符串末尾添加\0;该函数无法控制读取内容长度,存在越界风险。

int n=puts(char *str);输出字符串,自动换行,返回非负整数表示输出成功,EOF表示失败。

3、char *str=fgets(char *str,int ,FILE *);从文件中或者缓冲区stdin读取字符串,存入str字符数组中,读取长度为str长度-1,自动添加\0终止符。遇到\n终止读取,如果\n在字符数组长度范围内,换行符会被存入str并以\0结尾,如果\n刚好落在字符数组最后一位,将被转换为\0。当缓冲区字符串长度超过str长度,剩余的字符会留在缓冲区。

int n=fputs(char *str,FILE*);向文件或者输出流输出字符串str,不会自动换行,返回非负整数表示成功,EOF表示失败。

4、int n=fscanf(FILE*,格式化字符串,存入地址);从文件流或者输入流读取内容,可以是任意类型格式化字符串,存入相应的变量地址,返回值是读取变量的数量。当读取字符串时,遇到任意空字符(空格、制表符、换行符)均结束读取,空字符依然存在流中。返回值为读取数据个数,失败或者结尾返回EOF。

int n=fprintf(FILE*,format,变量名);向文件或者缓冲区输出数据,可以是任意类型变量,配合相应的格式化字符串。当输出字符串时,遇到\0结束,返回值为输出字符个数,失败返回EOF。

5、int getc(FILE *stream)和int putc(FILE *stream)两个函数,基本功能和getchar()/putchar一样,不仅用于终端单个字符的读取和输出,还能用于文件中单个字符的输入和输出。

C语言复习——文件操作以及各种输入输出相关推荐

  1. C语言进阶-文件操作超详解

    目录 为什么使用文件 什么是文件 分类(从文件功能的角度) 文件名 文件的打开和关闭 文件指针 fopen和fclose函数 打开方式表 文件的顺序读写 顺序读写函数表 什么是输入输出流 fgetc/ ...

  2. 【C 语言】文件操作 ( 配置文件读写 | 写出或更新配置文件 | 追加键值对数据 | 更新键值对数据 )

    文章目录 一.追加键值对数据 二.更新键值对数据 三.完整代码示例 一.追加键值对数据 在上一篇博客 [C 语言]文件操作 ( 配置文件读写 | 写出或更新配置文件 | 逐行遍历文件文本数据 | 获取 ...

  3. 【C 语言】文件操作 ( 按照单个字符的方式读写文件 | fgetc 函数 | fputc 函数 )

    文章目录 一.文件名路径设置 二.文件打开方式 三.fputc 函数 | 按照字符方式写文件 1.fputc 函数 2.代码示例 四.fgetc 函数 | 按照字符方式读文件 1.fgetc 函数 2 ...

  4. 【C 语言】文件操作 ( 学生管理系统 | 命令行接收数据填充结构体 | 结构体写出到文件中 | 查询文件中的结构体数据 )

    文章目录 一.学生管理系统 二.代码示例 一.学生管理系统 前两篇博客 [C 语言]文件操作 ( 将结构体写出到文件中并读取结构体数据 | 将结构体数组写出到文件中并读取结构体数组数据 ) [C 语言 ...

  5. 【C 语言】文件操作 ( 使用 fread 和 fwrite 实现二进制文件的拷贝 | stat 统计文件大小 | feof 判定文件结尾 )

    文章目录 一.stat 统计文件大小 二.feof 判定文件结尾 三.使用 fread 和 fwrite 实现二进制文件的拷贝 一.stat 统计文件大小 统计文件大小 , 需要借助 stat 结构体 ...

  6. c读取ini配置文件_Go-INI - 超赞的Go语言INI文件操作库

    INI 文件(Initialization File)是十分常用的配置文件格式,其由节(section).键(key)和值(value)组成,编写方便,表达性强,并能实现基本的配置分组功能,被各类软件 ...

  7. go 默认http版本_【每日一库】超赞的 Go 语言 INI 文件操作

    点击上方蓝色"Go语言中文网"关注我们,领全套Go资料,每天学习 Go 语言 如果你使用 INI 作为系统的配置文件,那么一定会使用这个库吧.没错,它就是号称地表 最强大.最方便  ...

  8. c语言数据文件是,C语言数据文件操作.ppt

    C语言数据文件操作 第十一章 文件 11.1 C文件概述 文件:存储在外部介质上数据的集合,是操作系统数据管理的单位 文件处理方法 缓冲文件系统:高级文件系统,系统自动为正在使用的文件开辟内存缓冲区 ...

  9. c语言课程设计 水电系统,广东工业大学水电费系统c语言设计(文件操作部分)

    广东工业大学水电费系统c语言设计(文件操作部分) (8页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 本人工作:主机和客户端的文件操作,主机 ...

最新文章

  1. vue之mapMutaions的使用 vuex中 action 用法示例 api.js的使用
  2. 手动部署OpenStack环境(五:新建网络及部署虚拟机)
  3. Linux多线程实践(3) --线程属性
  4. 数据挖掘建模之常见概率分布总结
  5. iOS-在团队开发过程中控制代码版本
  6. Duilib嵌入CEF以及JavaScript与C++交互
  7. php中文网侵权事件,【杂谈】程序员删库跑路事件,php中文网的几点声明!
  8. Java 泛型中的? super T和? extends T
  9. Unity教程之-Unity3d中针对Android Apk的签名验证(C#实现)
  10. 教你一种U盘病毒的快速检测方法
  11. C#:SQLite大量插入的效率问题
  12. 百度地图多点路线规划_自驾游路线规划神器:高德地图路书功能
  13. 系列课程 ElasticSearch 之第 6 篇 —— 自定义扩展分词文件、文档映射
  14. AliExpress国际速卖通唰信誉用什么虚拟卡用信可以成功扣款?
  15. --save-dev 与 --save的区别
  16. 联想Win10安装Ubuntu双系统教程
  17. module ‘cv2‘ has no attribute ‘face‘已安装仍报错解决
  18. 企业邮箱品牌哪家好?四大品牌企业邮箱推荐
  19. win10此电脑不见了_Win10如何把控制面板放到桌面上?Win10控制面板不见了解决方法...
  20. Java多线程同步和异步详解

热门文章

  1. 关于unity3D shader的UV理解
  2. 使用3DMAX制作一枚手雷
  3. 索尼最小最轻全画幅微单Alpha 7C面世
  4. vnc连接linux使用教程_远程管理之VNC 详解
  5. 微信小程序(7)说说微信小程序的发布流程?
  6. github项目推荐:少儿图形化编程启蒙游戏
  7. 计算机由哪几种显卡,各类显卡大比拼,你会选择哪一款显卡使用?
  8. 不习惯的 Vue3 起步六 の Echarts绘制下钻地图
  9. antd charts实现地图下钻
  10. 平均差误法中存在哪些误差?如何平衡这些误差?|小白心理-312/347考研答疑