C/C++文件操作————写文件与读文件以及通讯录的改进 (保姆级教学)

简介: C/C++文件操作————写文件与读文件以及通讯录的改进 (保姆级教学)

1.前言

        在前面我们写到过文件的打开与关闭用到了函数主要是fopen函数,参数是文件的文件名和打开方式,文件关闭函数fclose,参数是流,我们还讲到过流,今天我们讲解一些写文件与读文件函数以及对通讯录的改进还有一些文件的其他函数。

2.写文件函数与读文件函数

功能 函数名 适用于
字符输入函数 fgetc 所有输入流
字符输出函数 fputc 所有输出流
文本行输入函数 fgets 所有输入流
文本行输出函数 fputs 所有输出流
格式化输入函数 fscanf 所有输入流
格式化输出函数 fprintf 所有输出流
二进制输入 fread 文件
二进制输出 fwrite 文件

2.1fputc函数

       我们在cplusplus网中 fputc看到它的第一个参数是int  chararcter,这个含义是想要存储的字符信息,第二个参数是流在这里指fopen函数的返回值,fputc函数是将chararcter存入文件中,我们写一个代码将abcdef放到文件中,详细代码如下:

#include<stdio.h>
int main()
{
  FILE* pf = fopen("data.txt", "w");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  int i;
  for (i = 'a'; i <= 'f'; i++)
  {
    fputc(i, pf);
  }
  fclose(pf);
  pf = NULL;
  return 0;
}

我们运行后打开文件data.txt

我们可以看到abcdef已经写到了文件中 先打开文件,再利用循环利用写入字符函数fputc进行信息的存储。

2.2fgetc函数

       我们进入cplusplus网站fgetc我们看到它的参数是流,返回值是int类型,hfgetc函数的作用是读取文件的一个字符,我们写一个代码读取fputc函数存在文件的信息,详细代码如下:

#include<stdio.h>
int main()
{
  FILE* pf = fopen("data.txt", "r");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  int i,ch;
  for (i = 'a'; i <= 'f'; i++)
  {
    ch = fgetc(pf);
    printf("%c", ch);
  }
  fclose(pf);
  pf = NULL;
  return 0;
}

我们运行结果如下:

2.3fputs函数

        我们进入cplusplus网站fputs,函数的第一个参数是const char *str是将str中的内容传到文件中,第二个参数是流 ,返回类型是int,fputs函数的作用是将字符串传到文件中,我们写一个代码将字符串abcdefgh传到文件中,详细代码如下:

#include<stdio.h>
int main()
{
  FILE* pf = fopen("data.txt", "w");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  char arr[] = "abcdefgh";
  fputs(arr,pf);
  fclose(pf);
  pf = NULL;
  return 0;
}

运行后我们打开data.txt文件 可以看到

我们如果再次将arr内容改为ccc运行后打开data.txt文件

我们还可以看到打开文件后光标都在最前面,而且原来的信息也没有了,那我们是不是可以理解为写入文件是将原来的文件的内容覆盖, 然后写入信息。

2.4fgets函数

       我们进入cplusplus网站fgets看到它的第一个参数是char *str是读取文件后存放在程序的变量,第二个参数int num是在文件中读取几个字符+1,第三个参数是流,返回值是char*,例如我们想读取文件中的abcdefg,详细代码如下:

#include<stdio.h>
int main()
{
  FILE* pf = fopen("data.txt", "r");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  char arr[1006] ;
  char* p = arr;
  p = fgets(p, 7, pf);
  printf("%s", arr);
  fclose(pf);
  pf = NULL;
  return 0;
}

我们运行后可以看到

对于为什么是7,原因很简单,fgets函数会在最后将数组的第num个位置转化为’\0‘,我们进入调试可以看到

2.5fprintf函数

       我们进入 cplusplus网站fprintf 查看fprintf函数的参数,看到这个函数你是不是会想到printf函数,我们同样查看printf函数的参数

我们可以看到他们两个只差流这个参数,fprintf函数是格式化输入文件,我们写一个代码来展示一下这个函数的功能,代码如下:

#include<stdio.h>
struct num {
  float s;
  int i;
  char s1[10];
}S;
int main(){
  FILE* pf = fopen("data.txt", "w");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  S = { 1.23f,10,"wo" };
  fprintf(pf, "%f-%d-%s", S.s, S.i, S.s1);
  fclose(pf);
  pf = NULL;
  return 0;
}

我们运行程序后打开data.txt文件,可以看到

同样我们可以理解为将结构体S里面的内容,以  -  -  的形式输出到文件里。

2.6fscanf函数

        我们进入cplusplus网站fscanf查看fscanf函数的参数,看到fscanf函数我们很容易想到scanf函数,我们同样进入cplusplus网站查看scanf函数的参数,

我们可以看到这两个函数的参数只差了一个流, fscanf函数是将文件中有格式的信息储存在程序中定义的变量里,我们利用fprintf函数储存在文件的内容来初始化结构体S,详细代码如下:

#include<stdio.h>
struct num {
  float s;
  int i;
  char s1[10];
}S;
int main(){
  FILE* pf = fopen("data.txt", "r");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  fscanf(pf,"%f-%d-%s", &S.s, &S.i, &S.s1);
  printf("%f %d %s", S.s, S.i, S.s1);
  fclose(pf);
  pf = NULL;
  return 0;
}

我们运行代码,可以看到

2.7sprintf函数与sscanf函数

       sprintf函数是将数据以字符的形式存在s中, sscanf函数是将s的数据以字符的形式存在程序定义的变量中,我们写一个程序,代码如下:

#include<stdio.h>
struct num {
  int i;
  char arr;
  float f;
};
int main()
{
  struct num s = { 10,'c',1.2f};
  char arr[100] = { 0 };
  sprintf(arr, "%d%c%f", s.i, s.arr, s.f);
  struct num tmp = { 0 };
  sscanf(arr, "%d%c%f", &tmp.i, &tmp.arr, &tmp.f);
  printf("%d %c %f", tmp.i, tmp.arr, tmp.f);
  return 0;
}

运行结果如下:

2.8fwrite函数

       我们进入cplusplus网站fwrite的参数第一个参数是const void *ptr是指向的数据的地址,第二个参数size_t size是单个数据所占据的字节,第三个参数size_t count是要写进文件几个数据,第四个参数是流,特别注意这是以二进制的形式储存在文件中 ,我么们写一个代码展示一下函数的功能,代码如下:

#include<stdio.h>
struct num {
  int i;
  char arr[10];
  char brr[10];
};
int main()
{
  FILE* pf = fopen("data.txt", "w");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  struct num s = { 1,"abcd","efg" };
  fwrite(&s, sizeof(struct num), 1, pf);
  fclose(pf);
  pf = NULL;
  return 0;
}

我们运行代码后,打开data.txt文件可以看到:

由于是二进制的形式存储,所以有些信息我们不能识别。

2.9fread函数

        我们进入cplusplus网站看fread的参数一个参数是const void *ptr是要读取文件信息保存到,第二个参数size_t size是单个数据所占据的字节,第三个参数size_t count是要写进文件几个数据,第四个参数是流,我们读取上个函数的内容,代码如下:

#include<stdio.h>
struct num {
  int i;
  char arr[10];
  char brr[10];
};
int main()
{
  FILE* pf = fopen("data.txt", "r ");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  struct num s;
  fread(&s, sizeof(struct num), 1, pf);
  printf("%d\n%s\n%s", s.i, s.arr, s.brr);
  fclose(pf);
  pf = NULL;
  return 0;
}

运行程序后可以看到

3.通讯录的改进

在程序中加入函数

void init(Struct* pc)
{
  assert(pc);
  FILE* pf = fopen("data.txt", "r");
  if (pf == NULL)
  {
    perror("fopen");
    return;
  }
  while (fread(pc->arr + pc->i , sizeof(struct xinxi), 1, pf))
  {   
    pc->i++;
    addnum(pc);
  }
  fclose(pf);
  pf = NULL;
}

以及函数

void save(Struct* pc)
{
  assert(pc);
  FILE* pf = fopen("data.txt", "w");
  if (pf == NULL)
  {
    perror("fclose");
    return;
  }
  int i;
  for (i = 0; i < pc->i; i++)
  {
    fwrite(pc->arr + i, sizeof(struct xinxi), 1, pf);
  }
  fclose(pf);
  pf = NULL;
}

4.文件的随机读写

4.1fseek函数

根据文件指针的位置和偏移量来定位文件指针,第一个参数是流,第二个参数是偏移量v,第三个参数是相对位置,SEEK_SET是对于最初的位置,SEEK_CUR是对现在的位置,SEEK_END是对最后一位的位置。

我们写一个代码,如下:

#include<stdio.h>
int main()
{
  FILE* pf = fopen("data.txt", "r ");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  int ch;
  ch = fgetc(pf);
  printf("%c", ch);//a
  ch = fgetc(pf);
  printf("%c", ch);//b
  ch = fgetc(pf);
  printf("%c", ch);//c
  fseek(pf, -3, SEEK_CUR);
  ch = fgetc(pf);
  printf("%c", ch);//a
  fclose(pf);
  pf = NULL;
  return 0;
}

运行后为

这个函数有一定的局限性,我们必须对文件的内容非常熟悉,否则不容易输出我们想要的值。

4.2ftell函数

这个函数是计算相对于初始位置的偏移量 ,我们可以写一个代码,如下:

#include<stdio.h>
int main()
{
  FILE* pf = fopen("data.txt", "r ");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  fseek(pf, 0, SEEK_END);
  size_t sz = ftell(pf);
  printf("%d", sz);
  fclose(pf);
  pf = NULL;
  return 0;
}

运行结果为

4.3rewind函数

函数的功能是让指针指向初始位置,我们写一个代码,来展示一下它的功能:

#include<stdio.h>
int main()
{
  FILE* pf = fopen("data.txt", "r ");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  fseek(pf, -1, SEEK_END);
  int ch;
  ch = fgetc(pf);
  printf("%c\n", ch);
  rewind(pf);
  ch = fgetc(pf);
  printf("%c\n", ch);
  fclose(pf);
  pf = NULL;
  return 0;
}

运行结果为

文件的内容为

5.总结

       今天主要包括将数据传入文件的函数,以及将文件中的内容传到程序中的函数,还有一些对于文件中的指针以及偏移量的函数fseek函数,ftell函数,rewind函数的讲解,异界对通讯录的改造.今天的内容就结束了。

目录
相关文章
|
1月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
142 77
|
1月前
|
存储 C++
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
【数据结构——树】哈夫曼树(头歌实践教学平台习题)【合集】目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果:任务描述 本关任务:编写一个程序构建哈夫曼树和生成哈夫曼编码。 相关知识 为了完成本关任务,你需要掌握: 1.如何构建哈夫曼树, 2.如何生成哈夫曼编码。 测试说明 平台会对你编写的代码进行测试: 测试输入: 1192677541518462450242195190181174157138124123 (用户分别输入所列单词的频度) 预
59 14
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
|
1月前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
68 19
|
1月前
|
存储 人工智能 算法
【C++数据结构——图】最短路径(头歌教学实验平台习题) 【合集】
任务描述 本关任务:编写一个程序,利用Dijkstra算法,实现带权有向图的最短路径。 相关知识 为了完成本关任务,你需要掌握:Dijkst本关任务:编写一个程序,利用Dijkstra算法,实现带权有向图的最短路径。为了完成本关任务,你需要掌握:Dijkstra算法。带权有向图:该图对应的二维数组如下所示:Dijkstra算法:Dijkstra算法是指给定一个带权有向图G与源点v,求从v到G中其他顶点的最短路径。Dijkstra算法的具体步骤如下:(1)初始时,S只包含源点,即S={v},v的距离为0。
58 15
|
1月前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
50 13
|
1月前
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
48 12
|
1月前
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
46 10
|
1天前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
1月前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
50 5
|
1月前
|
存储 算法 搜索推荐
【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】
1. **相关排序和查找算法的原理**:介绍直接插入排序、直接选择排序、冒泡排序和顺序查找的基本原理及其实现代码。 2. **C++ 类与成员函数的定义**:讲解如何定义`Array`类,包括类的声明和实现,以及成员函数的定义与调用。 3. **数组作为类的成员变量的处理**:探讨内存管理和正确访问数组元素的方法,确保在类中正确使用动态分配的数组。 4. **函数参数传递与返回值处理**:解释排序和查找函数的参数传递方式及返回值处理,确保函数功能正确实现。 通过掌握这些知识,可以顺利地将排序和查找算法封装到`Array`类中,并进行测试验证。编程要求是在右侧编辑器补充代码以实现三种排序算法
40 5