写程序必会的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


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


相关文章
|
4天前
|
C语言
第一章 C语言知识点(程序)
第一章 C语言知识点(程序)
15 0
|
2天前
|
存储 程序员 C语言
C语言:文件操作
C语言:文件操作
9 1
|
3天前
|
存储 C语言 C++
【C语言】文件与文件操作
前言:我们通过学习的技术可以完成计算与字符串处理,但程序结束之后就都消失了,这样岂不可惜。我们通过文件与数据持久化保存相关的基础知识。
7 0
|
3天前
|
存储 自然语言处理 编译器
“ Hello world ”中的秘密之【C语言程序编译和链接】
作为C语言最经典的代码,大家都可以轻易写出。但是代码的运行过程却很少有人清楚,接下来我将介绍代码运行的奥秘。
15 0
|
4天前
|
存储 编译器 C语言
C语言中的文件操作指南
C语言中的文件操作指南
11 0
|
5天前
|
自然语言处理 编译器 C语言
C语言程序编译和链接
在ANSI C的任何⼀种实现中,存在两个不同的环境。 第1种是翻译环境,在这个环境中源代码被转换为可执⾏的机器指令(⼆进制指令)。 第2种是执⾏环境,它⽤于实际执⾏代码。
|
7天前
|
网络协议 物联网 数据处理
【C 言专栏】C 语言实现网络通信程序
【5月更文挑战第4天】本文探讨了使用C语言实现网络通信程序的方法,包括理解网络通信基本概念如协议和套接字,以及TCP/UDP通信的实现步骤。通过创建套接字、绑定端口、监听连接、数据传输和错误处理等关键环节,阐述了C语言在网络通信中的优势。文中还提到了实际应用案例、程序优化策略及未来发展趋势,旨在帮助读者掌握C语言在网络通信领域的应用技巧。
【C 言专栏】C 语言实现网络通信程序
|
9天前
|
并行计算 算法 测试技术
【C 言专栏】优化 C 语言程序性能的策略
【5月更文挑战第2天】本文探讨了优化C语言程序性能的策略,包括算法优化(选择合适的时间和空间复杂度)、代码结构优化(减少函数调用,合理使用循环)、内存管理优化(合理分配和及时释放内存)、编译器优化(选择优化级别,内联函数,循环展开)、数据结构优化(根据需求选择数组、哈希表或堆)、并行计算优化(多线程、多进程和MPI编程)以及性能测试与分析(使用性能分析工具、基准测试和分析执行路径)。通过这些方法,可以提升C语言程序的效率和运行速度。
|
10天前
|
算法 C语言
【C 言专栏】C 语言文件操作的技巧与方法
【4月更文挑战第30天】本文介绍了C语言文件操作的关键技巧,包括文件的打开与关闭(使用`fopen`和`fclose`函数),读取(`fgetc`、`fgets`和`fread`)和写入(`fputc`、`fputs`和`fwrite`)操作。此外,还讨论了文件指针移动(`fseek`)、错误处理、文件权限和格式等问题。文中提供了一个简单的读写文件的示例,并提到了高级技巧如随机访问、文件缓冲和截断。掌握这些技能将有助于提升C语言编程中的文件处理能力。
|
11天前
|
存储 Linux C语言
C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)-2
C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)