2025年4月1日 星期二 乙巳(蛇)年 正月初二 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > C语言

C语言从入门到精通保姆级教程(十三)

时间:07-25来源:作者:点击数:46

一次读写一块数据

  • C 语言己经从接口的层面区分了,文本的读写方式和二进制的读写方式。前面我们讲的是文本的读写方式。
  • 所有的文件接口函数,要么以 '\0',表示输入结束,要么以 '\n', EOF(0xFF)表示读取结束。'\0' '\n' 等都是文本文件的重要标识,而所有的二进制接口对于这些标识,是不敏感的。+二进制的接口可以读文本,而文本的接口不可以读二进制
  • 一次写入一块数据
函数声明 int fwrite(void *buffer, int num_bytes, int count, FILE *fp)
所在文件 stdio.h
函数功能 把buffer 指向的数据写入fp 指向的文件中
参数 char * buffer : 指向要写入数据存储区的首地址的指针
  int num_bytes: 每个要写的字段的字节数count
  int count : 要写的字段的个数
  FILE* fp : 要写的文件指针
返回值 int 成功,返回写的字段数;出错或文件结束,返回 0。
  • #include <stdio.h>
  • #include <string.h>
  • int main()
  • {
  •     FILE *fp = fopen("test.txt""wb+");
  •     // 注意: fwrite不会关心写入数据的格式
  •     char *str = "lnj\0it666";
  •      /*
  •      * 第一个参数: 被写入数据指针
  •      * 第二个参数: 每次写入多少个字节
  •      * 第三个参数: 需要写入多少次
  •      * 第四个参数: 已打开文件结构体指针
  •      */
  •     fwrite((void *)str, 91, fp);
  •     fclose(fp);
  •     return 0;
  • }
  • 一次读取一块数据
函数声明 int fread(void *buffer, int num_bytes, int count, FILE *fp)
所在文件 stdio.h
函数功能 把fp 指向的文件中的数据读到 buffer 中。
参数 char * buffer : 指向要读入数据存储区的首地址的指针
  int num_bytes: 每个要读的字段的字节数count
  int count : 要读的字段的个数
  FILE* fp : 要读的文件指针
返回值 int 成功,返回读的字段数;出错或文件结束,返回 0。
  • #include <stdio.h>
  • int main()
  • {
  •     // test.txt中存放的是"lnj\0it666"
  •     FILE *fr = fopen("test.txt""rb+");
  •     char buf[1024] = {0};
  •     // fread函数读取成功返回读取到的字节数, 读取失败返回0
  •     /*
  •      * 第一个参数: 存储读取到数据的容器
  •      * 第二个参数: 每次读取多少个字节
  •      * 第三个参数: 需要读取多少次
  •      * 第四个参数: 已打开文件结构体指针
  •      */ 
  •     int n = fread(buf, 11024, fr);
  •     printf("%i\n", n);
  •     for(int i = 0; i < n; i++){
  •         printf("%c", buf[i]);
  •     }
  •     fclose(fr);
  •     return 0;
  • }
  • 注意点:
  • 读取时num_bytes应该填写读取数据类型的最小单位, 而count可以随意写
  • 如果读取时num_bytes不是读取数据类型最小单位, 会引发读取失败
  • 例如: 存储的是char类型 6C 6E 6A 00 69 74 36 36 36 如果num_bytes等于1, count等于1024, 那么依次取出 6C 6E 6A 00 69 74 36 36 36 , 直到取不到为止 如果num_bytes等于4, count等于1024, 那么依次取出[6C 6E 6A 00][69 74 36 36] , 但是最后还剩下一个36, 但又不满足4个字节, 那么最后一个36则取不到
  • #include <stdio.h>
  • #include <string.h>
  • int main()
  • {
  •     // test.txt中存放的是"lnj\0it666"
  •     FILE *fr = fopen("test.txt""rb+");
  •     char buf[1024] = {0};
  •     /*
  •     while(fread(buf, 4, 1, fr) > 0){
  •         printf("%c\n", buf[0]);
  •         printf("%c\n", buf[1]);
  •         printf("%c\n", buf[2]);
  •         printf("%c\n", buf[3]);
  •     }
  •     */
  •     /*
  •     while(fread(buf, 1, 4, fr) > 0){
  •         printf("%c\n", buf[0]);
  •         printf("%c\n", buf[1]);
  •         printf("%c\n", buf[2]);
  •         printf("%c\n", buf[3]);
  •     }
  •     */
  •     while(fread(buf, 1, 1, fr) > 0){
  •         printf("%c\n", buf[0]);
  •     }
  •     fclose(fr);
  •     return 0;
  • }
  • 注意: fwrite和fread本质是用来操作二进制的
  • 所以下面用法才是它们的正确打开姿势
  • #include <stdio.h>
  • int main()
  • {
  •     FILE *fp = fopen("test.txt""wb+");
  •     int ages[4] = {1356};
  •     fwrite(ages, sizeof(ages), 1, fp);
  •     rewind(fp);
  •     int data;
  •     while(fread(&data, sizeof(int), 1, fp) > 0){
  •         printf("data = %i\n", data);
  •     }
  •     return 0;
  • }

读写结构体

  • 结构体中的数据类型不统一,此时最适合用二进制的方式进行读写
  • 读写单个结构体
  • #include <stdio.h>
  • typedef struct{
  •     char *name;
  •     int age;
  •     double height;
  • } Person;
  • int main()
  • {
  •     Person p1 = {"lnj"351.88};
  • //    printf("name = %s\n", p1.name);
  • //    printf("age = %i\n", p1.age);
  • //    printf("height = %lf\n", p1.height);
  •     FILE *fp = fopen("person.stu""wb+");
  •     fwrite(&p1, sizeof(p1), 1, fp);
  •     rewind(fp);
  •     Person p2;
  •     fread(&p2, sizeof(p2), 1, fp);
  •     printf("name = %s\n", p2.name);
  •     printf("age = %i\n", p2.age);
  •     printf("height = %lf\n", p2.height);
  •     return 0;
  • }
  • 读写结构体数组
  • #include <stdio.h>
  • typedef struct{
  •     char *name;
  •     int age;
  •     double height;
  • } Person;
  • int main()
  • {
  •     Person ps[] = {
  •       {"zs"181.65},
  •       {"ls"211.88},
  •       {"ww"331.9}
  •     };
  •     FILE *fp = fopen("person.stu""wb+");
  •     fwrite(&ps, sizeof(ps), 1, fp);
  •     rewind(fp);
  •     Person p;
  •     while(fread(&p, sizeof(p), 1, fp) > 0){
  •         printf("name = %s\n", p.name);
  •         printf("age = %i\n", p.age);
  •         printf("height = %lf\n", p.height);
  •     }
  •     return 0;
  • }
  • 读写结构体链表
  • #include <stdio.h>
  • #include <stdlib.h>
  • typedef struct person{
  •     char *name;
  •     int age;
  •     double height;
  •     struct personnext;
  • } Person;
  • Person *createEmpty();
  • void  insertNode(Person *head, char *name, int age, double height);
  • void printfList(Person *head);
  • int saveList(Person *head, char *name);
  • Person *loadList(char *name);
  • int main()
  • {
  • //    Person *head = createEmpty();
  • //    insertNode(head, "zs", 18, 1.9);
  • //    insertNode(head, "ls", 22, 1.65);
  • //    insertNode(head, "ws", 31, 1.78);
  • //    printfList(head);
  • //    saveList(head, "person.list");
  •     Person *head = loadList("person.list");
  •     printfList(head);
  •     return 0;
  • }
  • /**
  •  * @brief loadList 从文件加载链表
  •  * @param name 文件名称
  •  * @return  加载好的链表头指针
  •  */
  • Person *loadList(char *name){
  •     // 1.打开文件
  •     FILE *fp = fopen(name, "rb+");
  •     if(fp == NULL){
  •         return NULL;
  •     }
  •     // 2.创建一个空链表
  •     Person *head = createEmpty();
  •     // 3.创建一个节点
  •     Person *node = (Person *)malloc(sizeof(Person));
  •     while(fread(node, sizeof(Person), 1, fp) > 0){
  •         // 3.进行插入
  •         // 3.1让新节点的下一个节点 等于 头节点的下一个节点
  •         node->next = head->next;
  •         // 3.2让头结点的下一个节点 等于 新节点
  •         head->next = node;
  •         // 给下一个节点申请空间
  •         node = (Person *)malloc(sizeof(Person));
  •     }
  •     // 释放多余的节点空间
  •     free(node);
  •     fclose(fp);
  •     return head;
  • }
  • /**
  •  * @brief saveList 存储链表到文件
  •  * @param head 链表头指针
  •  * @param name 存储的文件名称
  •  * @return  是否存储成功 -1失败 0成功
  •  */
  • int saveList(Person *head, char *name){
  •     // 1.打开文件
  •     FILE *fp = fopen(name, "wb+");
  •     if(fp == NULL){
  •         return -1;
  •     }
  •     // 2.取出头节点的下一个节点
  •     Person *cur = head->next;
  •     // 3.将所有有效节点保存到文件中
  •     while(cur != NULL){
  •         fwrite(cur, sizeof(Person), 1, fp);
  •         cur = cur->next;
  •     }
  •     fclose(fp);
  •     return 0;
  • }
  • /**
  •  * @brief printfList 遍历链表
  •  * @param head 链表的头指针
  •  */
  • void printfList(Person *head){
  •     // 1.取出头节点的下一个节点
  •     Person *cur = head->next;
  •     // 2.判断是否为NULL, 如果不为NULL就开始遍历
  •     while(cur != NULL){
  •         // 2.1取出当前节点的数据, 打印
  •         printf("name = %s\n", cur->name);
  •         printf("age = %i\n", cur->age);
  •         printf("height = %lf\n", cur->height);
  •         printf("next = %x\n", cur->next);
  •         printf("-----------\n");
  •         // 2.2让当前节点往后移动
  •         cur = cur->next;
  •     }
  • }
  • /**
  •  * @brief insertNode 插入新的节点
  •  * @param head 链表的头指针
  •  * @param p 需要插入的结构体
  •  */
  • void  insertNode(Person *head, char *name, int age, double height){
  •     // 1.创建一个新的节点
  •     Person *node = (Person *)malloc(sizeof(Person));
  •     // 2.将数据保存到新节点中
  •     node->name = name;
  •     node->age = age;
  •     node->height = height;
  •     // 3.进行插入
  •     // 3.1让新节点的下一个节点 等于 头节点的下一个节点
  •     node->next = head->next;
  •     // 3.2让头结点的下一个节点 等于 新节点
  •     head->next = node;
  • }
  • /**
  •  * @brief createEmpty 创建一个空链表
  •  * @return 链表头指针, 创建失败返回NULL
  •  */
  • Person *createEmpty(){
  •     // 1.定义头指针
  •     Person *head = NULL;
  •     // 2.创建一个空节点, 并且赋值给头指针
  •     head = (Person *)malloc(sizeof(Person));
  •     if(head == NULL){
  •         return head;
  •     }
  •     head->next = NULL;
  •     // 3.返回头指针
  •     return head;
  • }

其它文件操作函数

  • ftell 函数
函数声明 long ftell ( FILE * stream );
所在文件 stdio.h
函数功能 得到流式文件的当前读写位置,其返回值是当前读写位置偏离文件头部的字节数.
参数及返回解析  
参数 FILE * 流文件句柄
返回值 int 成功,返回当前读写位置偏离文件头部的字节数。失败, 返回-1
  • #include <stdio.h>
  • int main()
  • {
  •     char *str = "123456789";
  •     FILE *fp = fopen("test.txt""w+");
  •     long cp = ftell(fp);
  •     printf("cp = %li\n", cp); // 0
  •     // 写入一个字节
  •     fputc(str[0], fp);
  •     cp = ftell(fp);
  •     printf("cp = %li\n", cp); // 1
  •     fclose(fp);
  •     return 0;
  • }
  • rewind 函数
函数声明 void rewind ( FILE * stream );
所在文件 stdio.h
函数功能 将文件指针重新指向一个流的开头。  
参数及返回解析  
参数 FILE * 流文件句柄
返回值 void 无返回值
  • #include <stdio.h>
  • int main()
  • {
  •     char *str = "123456789";
  •     FILE *fp = fopen("test.txt""w+");
  •     long cp = ftell(fp);
  •     printf("cp = %li\n", cp); // 0
  •     // 写入一个字节
  •     fputc(str[0], fp);
  •     cp = ftell(fp);
  •     printf("cp = %li\n", cp); // 1
  •     // 新指向一个流的开头
  •     rewind(fp);
  •     cp = ftell(fp);
  •     printf("cp = %li\n", cp); // 0
  •     fclose(fp);
  •     return 0;
  • }
  • fseek 函数
函数声明 int fseek ( FILE * stream, long offset, int where);
所在文件 stdio.h
函数功能 偏移文件指针。
参数及返回解析  
参 数 FILE * stream 文件句柄
  long offset 偏移量
  int where 偏移起始位置
返回值 int 成功返回 0 ,失败返回-1
  • 常用宏
  • #define SEEK_CUR 1 当前文字
  • #define SEEK_END 2 文件结尾
  • #define SEEK_SET 0 文件开头
  • #include <stdio.h>
  • int main()
  • {
  •     FILE *fp = fopen("test.txt""w+");
  •     fputs("123456789", fp);
  •     // 将文件指针移动到文件结尾, 并且偏移0个单位
  •     fseek(fp, 0, SEEK_END);
  •     int len = ftell(fp); // 计算文件长度
  •     printf("len = %i\n", len);
  •     fclose(fp);
  •     return 0;
  • }
  • #include <stdio.h>
  • int main()
  • {
  •     FILE *fp;
  •    fp = fopen("file.txt","w+");
  •    fputs("123456789", fp);
  •    fseek( fp, 7, SEEK_SET );
  •    fputs("lnj", fp);
  •    fclose(fp);
  •     return 0;
  • }
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐