写程序必会的C语言文件操作(上)附手绘图详解

简介: 写程序必会的C语言文件操作(上)附手绘图详解

1. 为什么使用文件


在之前我们写过一个通讯录的博客,在通讯录里我们可以随意增删查改人员的信息,可是此时数据的信息是存放到内存中的,一旦程序退出,数据也将不复存在。下次使用通讯录时,就需要重新录入数据。

我们希望输入的数据可以一直存在,除非我们主动选择删除。这就涉及到了数据的持久化问题。

我们一般进行数据持久化的方式有将数据存放到磁盘,存放到数据库等。

而我们可以直接将数据存储文件里,再将文件存到电脑的硬盘上,就可以做到数据的持久化。


2. 什么是文件


磁盘上的文件就是文件。


然而在程序设计中,我们所谈的文件有两种,一种是程序文件,另一种是数据文件(从文件功能的角度来分类的)。


2.1 程序文件


程序文件又包含源程序文件(后缀为.c),目标文件(Windows环境后缀为.obj),可执行程序(Windows环境后缀为.exe)。


2.2 数据文件


程序文件的数据信息需要存放到数据文件中,我们既可以从程序文件往数据文件里写(输出)信息,也可以从数据文件中向程序文件往外读(输入)信息。


咱们之前所处理数据的输入输出都是以终端为对象的,即从终端的键盘读入数据,运行结果到显示器上,数据是存放到内存里面的。


be97030bf0f2cf7ac1c3be8671677c72_f8f88186cc7e4949862ab3686e80b7e0.png


作了图方便大家理解。


其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理 的就是磁盘上文件。


那我们应该怎么把内存中的东西写入文件中呢?


2.3 文件名


一个文件要有一个独有的文件标识,便于用户识别和引用。


文件标识包含文件路径,文件名主干和文件后缀。


例如: f:\class\test.txt


其中 f:\class\是文件路径,test是文件名主干,.txt是文件后缀。


为了方便起见,文件标识常被称为文件名。


3. 文件的打开和关闭


3.1 文件指针


缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。


每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息。


这个文件信息区究竟是什么类型呢?让我们在VS编译器中stdio.h文件中搜寻一番。


fcd6cf6a44fdb0fc946baf8804f7cdb4_dec9f0ef54a343278968ac3e15228d04.png


可以看到,这些信息是保存在一个结构体变量中的。该结构体类型是由系统 声明的,取名FILE。


不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。


我们一般可以通过一个FILE指针来维护FILE结构的变量。


下面我们创建一个FILE*的指针变量。


3.2 文件的打开和关闭实例


我们在试着以只读的方式在桌面上打开一个叫“你快乐吗”的文件。


如果文件不存在,打印错误,并返回一个空指针。


#include<stdio.h>
int main()
{
  FILE *pf=fopen("C:\\Users\\HP\\Desktop\\你快乐吗.txt", "r");
  if (pf == NULL)
  {
  perror("fopen");
  return 1;
  }
  fclose(pf);
  pf == NULL;
  return 0;
}

2b350c7b288a2621dcf4a0b888dbe0f2_54f8d1c9800f46c4986ae77e7305d290.png


如图,提示没有这个文件。


我们这次以只写“w”的方式打开文件。只写方式如果指定文件不存在,建立一个新的文件。


#include<stdio.h>
int main()
{
  FILE *pf=fopen("C:\\Users\\HP\\Desktop\\你快乐吗.txt", "w");
  if (pf == NULL)
  {
  perror("fopen");
  return 1;
  }
  fclose(pf);
  pf == NULL;
  return 0;
}


642ddd5666c2c1b0da163ef0f5ae8a39_5363b0899acb44f292b0431251d0122d.png


程序没有报错。


b1a3fc4247ce0d8808e3fa9d6052bdaf_54a9a8294df3494081dd806cc373c66b.png


回到桌面,我们创建了一个名叫“你快乐吗”的文件,这个文件本来是没有的。


4. 文件的顺序读写


字符输入函数 fgetc


我们使用字符输入函数fgetc向上面的文件里写入26个英文字母。


#include<stdio.h>
int main()
{
  FILE *pf=fopen("C:\\Users\\HP\\Desktop\\你快乐吗.txt", "w");
  if (pf == NULL)
  {
  perror("fopen");
  return 1;
  }
  int i = 0;
  for (i = 0; i < 26; i++)
  {
  fputc('a'+i, pf);
  }
  fclose(pf);
  pf == NULL;
  return 0;
}


643502122efc677a3046375a2d8e3e5b_cd7ea51cf4bf4867897a565c7e159e91.png


上面程序运行完之后,文件里出现26个英文字母。


int fgetc ( FILE * stream );

函数的返回类型是int,即返回一个ASCII值,读取错误返回一个EOF。


我们也可以从文件里读出数据。


改成只读的形式后用fgetc读取之后打印出来,我们可以这样写。


#include<stdio.h>
int main()
{
  FILE *pf=fopen("C:\\Users\\HP\\Desktop\\你快乐吗.txt", "r");
  if (pf == NULL)
  {
  perror("fopen");
  return 1;
  }
  int i = 0;
  int ch = 0;
  for (i = 0; i < 26; i++)
  {
  ch=fgetc(pf);
  printf("%c ", ch);
  }
  fclose(pf);
  pf == NULL;
  return 0;
}


运行结果:


be7a8cb8df80382751643bd254f3b642_70bc29ecfcc643f988f412c2d8057429.png


可以看出,fgetc函数读完一个值后,会让指针向后移一位。


文本行输出函数 fputs


用fputs可以操作字符串内容。


#include<stdio.h>
int main()
{
  FILE *pf=fopen("C:\\Users\\HP\\Desktop\\你快乐吗.txt", "w");
  if (pf == NULL)
  {
  perror("fopen");
  return 1;
  }
  fputs("hello world", pf);
  fclose(pf);
  pf == NULL;
  return 0;
}


34ef37baa3dcdf5aeae92cd4a3163aa1_b80b791bd78e4788bb72eb0bbaf9cafc.png


文本行输入函数 fgets


用fgets读取数据到内存。


char * fgets ( char * str, int num, FILE * stream );

实际上它所读取到的数据比我们所输入的数据少一个,比如我们输入num为5,那么它只能读4个数据。


#include<stdio.h>
int main()
{
  FILE *pf=fopen("C:\\Users\\HP\\Desktop\\你快乐吗.txt", "r");
  if (pf == NULL)
  {
  perror("fopen");
  return 1;
  }
  char arr[20];
  fgets(arr, 5, pf);
  printf("%s", arr);
  fclose(pf);
  pf == NULL;
  return 0;
}


574410dc1e02c09d42e2e1ee9f99a7a6_161af17222584c429315be4bbf2d4e6d.png


如图,只读取了4个字母。


格式化输出函数 fprintf


int fprintf ( FILE * stream, const char * format, ... );

fprintf是将数据写入文件的函数,我们直接看代码。


#include<stdio.h>
struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 111,5.55f,"chendadachen" };
  FILE *pf=fopen("C:\\Users\\HP\\Desktop\\你快乐吗.txt", "w");
  if (pf == NULL)
  {
  perror("fopen");
  return 1;
  }
  fprintf(pf, "%d %f %s", s.n, s.f, s.arr);
  fclose(pf);
  pf == NULL;
  return 0;
}


运行结果如下,结构体的数据成功输入。


e08e12aa9e363249a43df8c02d9e6482_c03a71afd5d340c4951416c5ca26919c.png


格式化输入函数 fscanf


我们这次将结构体置空,从上面的文件中读取信息然后打印到屏幕上。


#include<stdio.h>
struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 0 };
  FILE *pf=fopen("C:\\Users\\HP\\Desktop\\你快乐吗.txt", "r");
  if (pf == NULL)
  {
  perror("fopen");
  return 1;
  }
  fscanf(pf, "%d %f %s", &(s.n), &(s.f), s.arr);
  printf("%d %f %s\n", s.n, s.f, s.arr);
  fclose(pf);
  pf == NULL;
  return 0;
}


数据成功读入。


37c97ffa1cc6e956cc81c4f2ccf17e8e_db905f11f1df44148514f37c7d8be88d.png


sprintf


把一个格式化的数据写到字符串中


int sprintf ( char * str, const char * format, ... );
sprintf 可以将一个结构体转换成字符串。
#include<stdio.h>
struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 111,5.55f,"chendadachen"};
  char a[200] = { 0 };
  sprintf(a, "%d %f %s", s.n, s.f, s.arr);
  printf("%s\n", a);
  return 0;
}


688773273475f881cc12e9d24022ed01_ac7fa3ab6ab74ba5ab6a325fa5891b1e.png


如图,以字符串的形式打印成功。


有没有办法还原回去呢?这就需要下面的sscanf了。


sscanf


将字符串转换成格式化的数据


#include<stdio.h>
struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 111,5.55f,"chendadachen"};
  char a[200] = { 0 };
  sprintf(a, "%d %f %s", s.n, s.f, s.arr);
  printf("字符串的数据:%s\n", a);
  struct S tmp = { 0 };
  sscanf(a, "%d %f %s", &(tmp.n), &(tmp.f), tmp.arr);
  printf("格式化的数据:%d %f %s", tmp.n, tmp.f, tmp.arr);
  return 0;
}


4e586b83e352d3709b9b15884415ecf5_be4450b1234143868495ddbc003fda00.png


这篇博客旨在总结我自己阶段性的学习,要是能帮助到大家,那可真是三生有幸!如果觉得我写的不错的话还请点个赞和关注哦~我会持续输出编程的知识的!😘😘😘


相关文章
|
23天前
|
存储 程序员 C语言
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
43 9
|
25天前
|
存储 数据管理 C语言
C 语言中的文件操作:数据持久化的关键桥梁
C语言中的文件操作是实现数据持久化的重要手段,通过 fopen、fclose、fread、fwrite 等函数,可以实现对文件的创建、读写和关闭,构建程序与外部数据存储之间的桥梁。
|
27天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
53 5
|
27天前
|
C语言
C语言编程中,错误处理至关重要,能提升程序的健壮性和可靠性
C语言编程中,错误处理至关重要,能提升程序的健壮性和可靠性。本文探讨了C语言中的错误类型(如语法错误、运行时错误)、基本处理方法(如返回值、全局变量、自定义异常处理)、常见策略(如检查返回值、设置标志位、记录错误信息)及错误处理函数(如perror、strerror)。强调了不忽略错误、保持处理一致性及避免过度处理的重要性,并通过文件操作和网络编程实例展示了错误处理的应用。
59 4
|
27天前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
96 3
|
26天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
57 1
|
27天前
|
网络协议 物联网 数据处理
C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势
本文探讨了C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势。文章详细讲解了使用C语言实现网络通信程序的基本步骤,包括TCP和UDP通信程序的实现,并讨论了关键技术、优化方法及未来发展趋势,旨在帮助读者掌握C语言在网络通信中的应用技巧。
38 2
|
27天前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
37 1
|
1月前
|
存储 C语言
【c语言】玩转文件操作
本文介绍了C语言中文件操作的基础知识,包括文件的打开和关闭、文件的顺序读写、文件的随机读写以及文件读取结束的判定。详细讲解了`fopen`、`fclose`、`fseek`、`ftell`、`rewind`等函数的使用方法,并通过示例代码展示了如何进行文件的读写操作。最后,还介绍了如何判断文件读取结束的原因,帮助读者更好地理解和应用文件操作技术。
47 2
|
2月前
|
存储 C语言
C语言文件操作(2)
【10月更文挑战第2天】