【C语言】可以不用,但不能不会的——文件操作(附上高阶版本通讯录)(三)

简介: 【C语言】可以不用,但不能不会的——文件操作

🎄文件的随机读写

再说接下来的操作之前,先明确一个东西:

文件偏移量(刚打开的文件偏移量为0)


🎅fseek

描述

C 库函数 int fseek(FILE *stream, long int offset, int whence) 设置流 stream 的文件位置为给定的偏移 offset参数 offset 意味着从给定的 whence 位置查找的字节数

声明

int fseek(FILE *stream, long int offset, int whence)

参数

  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  • offset – 这是相对 whence 的偏移量,以 字节为单位。
  • whence – 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:
常量 描述
SEEK_SET 文件的开头
SEEK_CUR 文件指针的当前位置
SEEK_END 文件的末尾


返回值

如果成功,则该函数返回零,否则返回非零值。

使用实例

4c74e80faebd4859a7bf1a42de97f5a5.png

🎅ftell

描述

C 库函数 long int ftell(FILE *stream) 返回给定流 stream 的当前文件位置

声明

long int ftell(FILE *stream)

参数

  • stream– 这是指向 FILE 对象的指针,该 FILE 对象标识了流。

返回值

该函数返回位置标识符的当前值。如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值。

使用实例

4931abc6bff34929a4fa6fe6b30b0471.png

🎅rewind

描述

C 库函数 void rewind(FILE *stream) 设置文件位置为给定流 stream 的文件的开头

声明

void rewind(FILE *stream)

参数

stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。

返回值

该函数 不返回任何值

使用实例

aaeaee6b2ecc41a58063b064097ef03d.png

🎄文件结束的判定


❗❗❗❗❗被错误使用的 feof

牢记:在文件读取过程中,不能feof函数的返回值直接用来判断文件的是否结束。

而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束

🐂1. 文本文件读取是否结束,判断返回值是否为EOF (fgetc),或NULL(fgets)

例如:

  • fgetc判断是否为EOF.
  • fgets判断返回值是否为NULL.

🐂2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。

例如:

  • fread判断返回值是否小于实际要读的个数

正确的使用:

1.文本文件的例子:

#include <stdio.h>
#include <stdlib.h>
int main(void) {
    int c; // 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if(!fp) {
        perror("File opening failed");
        return EXIT_FAILURE;
   }
 //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
   { 
       putchar(c);
   }
 //判断是什么原因结束的
    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);
}

2.二进制文件的例子:

#include <stdio.h>
enum { SIZE = 5 };
int main(void) {
    double a[SIZE] = {1.0,2.0,3.0,4.0,5.0};
    double b = 0.0;
    size_t ret_code = 0;
    FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
    fwrite(a, sizeof(*a), SIZE, fp); // 写 double 的数组
    fclose(fp);
    fp = fopen("test.bin","rb");
    // 读 double 的数组
    while((ret_code = fread(&b, sizeof(double), 1, fp))>=1)
   {
        printf("%lf\n",b);
   }
    if (feof(fp))
        printf("Error reading test.bin: unexpected end of file\n");
    else if (ferror(fp)) {
        perror("Error reading test.bin");
   }
    fclose(fp);
    fp = NULL; }

🐂🐸通讯录高阶版(动态内存+自定义类型+文件)

contact.c

#include "contact.h"
//静态初始化
//void InitContact(struct Contact* pc)
//{
//  pc->sz = 0;//默认没有信息
//  memset(pc->data, 0, MAX*sizeof(struct PeoInfo));
//  memset(pc->data, 0, sizeof(pc->data));
//}
void CheckCapacity(struct Contact* pc)
{
  if (pc->sz == pc->capacity)
  {
    struct PeoInfo* ptr = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
    if (ptr != NULL)
    {
      pc->data = ptr;
      pc->capacity += 2;
      printf("增容成功\n");
    }
    else
    {
      printf("增容失败\n");
      return;
    }
  }
}
//加载数据
void LoadContact(struct Contact* pc)
{
  FILE*pf = fopen("contact.txt", "r");
  if (NULL == pf)
  {
    perror("LoadContact::fopen");
    return;
  }
  struct PeoInfo temp = { 0 };
  while(EOF != fscanf(pf, "%s %d %s %s %s", temp.name, &temp.age, temp.sex, temp.tele, temp.addr))
    {
      CheckCapacity(pc);
      pc->data[pc->sz] = temp;
      pc->sz++;
    }
  fclose(pf);
  pf = NULL;
}
//动态初始化
void InitContact(struct Contact* pc)
{
  pc->sz = 0;
  pc->data = (struct PeoInfo*)malloc(DEFAULT_SZ * sizeof(struct PeoInfo));
  pc->capacity = DEFAULT_SZ;//初始最大容量为3
  //加载文件信息
  LoadContact(pc);
}
//静态添加
//void AddContact(struct Contact* pc)
//{
//  if (pc->sz == MAX)
//  {
//    printf("通讯录满了\n");
//  }
//  else
//  {
//    printf("请输入名字:>");
//    scanf_s("%s", pc->data[pc->sz].name, 30);
//    printf("请输入年龄:>");
//    scanf_s("%d", &(pc->data[pc->sz].age));
//    printf("请输入性别:>");
//    scanf_s("%s", pc->data[pc->sz].sex, 5);
//    printf("请输入电话:>");
//    scanf_s("%s", pc->data[pc->sz].tele, 12);
//    printf("请输入地址:>");
//    scanf_s("%s", pc->data[pc->sz].addr, 30);
//
//
//    printf("添加成功\n");
//    pc->sz++;
//    ShowContact(pc);
//  }
//}
//动态添加
void AddContact(struct Contact* pc)
{
  if (pc->sz == pc->capacity)
  {
    struct PeoInfo* ptr = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
    if (ptr != NULL)
    {
      pc->data = ptr;
      pc->capacity += 2;
      printf("增容成功\n");
    }
    else
    {
      printf("增容失败\n");
      return;
    }
  }
  //录入新增人的信息
      printf("请输入名字:>");
    scanf_s("%s", pc->data[pc->sz].name, 30);
    printf("请输入年龄:>");
    scanf_s("%d", &(pc->data[pc->sz].age));
    printf("请输入性别:>");
    scanf_s("%s", pc->data[pc->sz].sex, 5);
    printf("请输入电话:>");
    scanf_s("%s", pc->data[pc->sz].tele, 12);
    printf("请输入地址:>");
    scanf_s("%s", pc->data[pc->sz].addr, 30);
    printf("添加成功\n");
    pc->sz++;
    ShowContact(pc);
}
void DeletContact(struct Contact* pc)
{
  printf("请输入需要删除的联系人姓名\n");
  char name[30] = "0";
  scanf_s("%s", name, 30);
  for (int i = 0; i < pc->sz; i++)
  {
    if (strcmp(name, pc->data[i].name) == 0)
    {
      for (int j = i; j < pc->sz-1; j++)
      {
        strcpy_s(pc->data[j].name, 30, pc->data[j + 1].name);
        strcpy_s(pc->data[j].sex, 5, pc->data[j + 1].sex);
        strcpy_s(pc->data[j].tele, 12, pc->data[j + 1].tele);
        strcpy_s(pc->data[j].addr, 30, pc->data[j + 1].addr);
        pc->data[j].age = pc->data[j + 1].age;
      }
      printf("删除成功\n");
      (pc->sz)--;
      ShowContact(pc);
    }
  }
}
void ModifyContact(struct Contact* pc)
{
  printf("请输入需要修改的联系人姓名\n");
  char name[30] = "0";
  scanf_s("%s", name, 30);
  for (int i = 0; i < pc->sz; i++)
  {
    if (strcmp(name, pc->data[i].name) == 0)
    {
      printf("请输入名字:>");
      scanf_s("%s", pc->data[i].name, 30);
      printf("请输入年龄:>");
      scanf_s("%d", &(pc->data[i].age));
      printf("请输入性别:>");
      scanf_s("%s", pc->data[i].sex, 5);
      printf("请输入电话:>");
      scanf_s("%s", pc->data[i].tele, 12);
      printf("请输入地址:>");
      scanf_s("%s", pc->data[i].addr, 30);
      printf("修改成功!\n");
      ShowContact(pc);
    }
  }
}
void ShowContact(struct Contact* pc)
{
  int i = 0;
  printf("序号\t%10s\t%10s\t%8s\t%15s\t%30s\n", "name", "age", "sex", "tele", "addr");
  for (i = 0; i < pc->sz ; i++)
  {
    //打印每一个数据
    printf("%d\t%10s\t%10d\t%8s\t%15s\t%30s\n",
      i + 1,
      pc->data[i].name,
      pc->data[i].age,
      pc->data[i].sex,
      pc->data[i].tele,
      pc->data[i].addr);
  }
}
void SearchContact(struct Contact* pc)
{
  printf("请输入需要搜索的联系人姓名\n");
  char name[30] = "0";
  scanf_s("%s", name, 30);
  for (int i = 0; i < pc->sz; i++)
  {
    if (strcmp(name, pc->data[i].name) == 0)
    {
      printf("序号\t%10s\t%10s\t%8s\t%15s\t%30s\n", "name", "age", "sex", "tele", "addr");
      printf("%d\t%10s\t%10d\t%8s\t%15s\t%30s\n",
        i + 1,
        pc->data[i].name,
        pc->data[i].age,
        pc->data[i].sex,
        pc->data[i].tele,
        pc->data[i].addr);
      return;
    }
  }
  printf("找不到联系人信息\n");
}
void SortContact(struct Contact* pc)
{
  struct PeoInfo temp;
  for (int j = 0; j < pc->sz - 1; j++)
    for (int i = 0; i < pc->sz - 1 - j; i++)
    {
      if (strcmp(pc->data[i].name, pc->data[i + 1].name) > 0)
      {
        temp = pc->data[i + 1];
        pc->data[i + 1] = pc->data[i];
        pc->data[i] = temp;
      }
    }
  ShowContact(pc);
}
void DestroyContact(struct Contact* pc)
{
  free(pc->data);
  pc->data = NULL;
  pc->capacity = 0;
  pc->sz = 0;
}
void SaveContact(struct Contact* pc)
{
  FILE* pf = fopen("contact.txt", "w");
  if (NULL == pf)
  {
    perror("SaveContact::fopen");
    return;
  }
  int i = 0;
  for (i = 0; i < pc->sz; i++)
  {
    fprintf(pf, "%s   %d   %s   %s   %s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
  }
  fclose(pf);
  pf = NULL;
}

contact.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#define NAME_MAX 30
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
#define MAX 1000
#define DEFAULT_SZ 3 //默认大小为3
#include <string.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//创建枚举变量
enum Option
{
  EXIT,
  ADD,
  DEL,
  SEARCH,
  MODIFY,
  SHOW,
  SORT
};
//描述人的信息
struct PeoInfo
{
  char name[NAME_MAX];
  int age;
  char sex[SEX_MAX];
  char tele[TELE_MAX];
  char addr[ADDR_MAX];
};
//通讯录-静态版本
//struct Contact
//{
//  struct PeoInfo data[MAX];//1000个人的数据存放在data数组中
//  int sz;//记录当前通讯录有效信息的个数
//};
//动态增长的版本
struct Contact
{
  struct PeoInfo* data;
  int sz;//通讯录中当前有效元素的个数
  int capacity;//通讯录的当前最大容量
};
//初始化通讯录
void InitContact(struct Contact* pc);
//增加联系人
void AddContact(struct Contact* pc);
//删除联系人
void DeletContact(struct Contact* pc);
//修改联系人信息
void ModifyContact(struct Contact* pc);
//搜索联系人信息
void SearchContact(struct Contact* pc);
//显示所有的联系人
void ShowContact(struct Contact* pc);
//按姓氏排序联系人信息
void SortContact(struct Contact* pc);
//销毁通讯录
void DestroyContact(struct Contact* pc);
//保存通讯录信息
void SaveContact(struct Contact* pc);
//加载文件信息
void LoadContact(struct Contact* pc);
//增容
void CheckCapacity(struct Contact* pc);

通讯录(动态内存版本).c

#include "contact.h"
void menu()  
{
  printf("******************************\n");
  printf("****  1. 添加      2. 删除  **\n");
  printf("****  3. 搜索      4. 修改  **\n");
  printf("****  5. 展示全部  6. 排序  **\n");
  printf("****  0. 退出               **\n");
  printf("******************************\n");
}
int main()
{
  int input = 0;
  //创建一个通讯录
  struct Contact con;
  //初始化通讯录
  InitContact(&con);
  do
  {
    menu();
    printf("请选择:>");
    scanf_s("%d", &input);
    switch (input)
    {
    case ADD:
      AddContact(&con);
      break;
    case DEL:
      DeletContact(&con);
      break;
    case SHOW:
      ShowContact(&con);
      break;
    case MODIFY:
      ModifyContact(&con);
      break;
    case SEARCH:
      SearchContact(&con);
      break;
    case SORT:
      SortContact(&con);
      break;
    case EXIT:
      //销毁通讯录
      SaveContact(&con);
      DestroyContact(&con);
      printf("保存成功\n退出通讯录\n");
      break;
    default:
      printf("选择错误\n");
      break;
    }
  } while (input);
  return 0;
}

❤原创不易,如有错误,欢迎评论区留言指出,感激不尽❤

❤如果觉得内容不错,给个三连不过分吧~                       ❤

❤看到会回访~                                                                   ❤


相关文章
|
4天前
|
C语言
【C语言基础】:文件操作详解(后篇)-2
【C语言基础】:文件操作详解(后篇)
|
4天前
|
存储 C语言
【C语言基础】:文件操作详解(后篇)-1
【C语言基础】:文件操作详解(后篇)
|
4天前
|
存储 C语言 C++
【C语言基础】:文件操作详解(前篇:准备知识)
【C语言基础】:文件操作详解(前篇:准备知识)
|
4天前
|
存储 C语言 Windows
C语言——文件操作
C语言——文件操作
3 0
|
5天前
|
机器学习/深度学习 搜索推荐 程序员
C语言实现个人通讯录(功能优化)-2
C语言实现个人通讯录(功能优化)
C语言实现个人通讯录(功能优化)-2
|
5天前
|
存储 C语言 索引
C语言实现个人通讯录(功能优化)-1
C语言实现个人通讯录(功能优化)
C语言实现个人通讯录(功能优化)-1
|
7天前
|
Linux API C语言
C语言读写BMP文件-EasyBmp【 linux 平台】
**EasyBmp** 是一个49KB的轻量级C++图像处理库,专注于BMP格式,提供简单易用的API。它的特点是小巧、开源、易于理解和高度定制。通过示例代码展示了如何轻松读取、缩放和保存BMP图像。适合需要高效处理BMP图像的开发者。
|
7天前
|
存储 C语言
C语言进阶 文件操作知识(下)
C语言进阶 文件操作知识(下)
12 2
|
7天前
|
数据库 C语言
C语言进阶 文件操作知识(上)
C语言进阶 文件操作知识(上)
10 3
|
12天前
|
C语言
C语言进阶——sprintf与sscanf、文件的随机读写(fseek、ftell、rewind)
C语言进阶——sprintf与sscanf、文件的随机读写(fseek、ftell、rewind)
6 0