文件(上)——“C”

简介: 文件(上)——“C”

位CSDN的uu们你们好呀,今天,小雅兰的内容是C语言中的文件操作,下面,就让我们进入文件的世界吧


为什么使用文件


什么是文件


               程序文件


               数据文件


               文件名


文件的打开和关闭


               文件指针


               文件的打开和关闭


文件的顺序读写


为什么使用文件


小雅兰之前写过静态版通讯录和动态版通讯录,是因为当时学习到了结构体的知识点,当通讯录运行起来的时候,可以给通讯录中增加、删除数据,此时数据是存放在内存中,当程序退出的时候,通讯录中的数据自然就不存在了,等下次运行通讯录程序的时候,数据又得重新录入,如果使用这样的通讯录就很难受。


静态版通讯录——“C”_认真学习的小雅兰.的博客-CSDN博客


动态版通讯录——“C”_认真学习的小雅兰.的博客-CSDN博客


我们在想既然是通讯录就应该把信息记录下来,只有我们自己选择删除数据的时候,数据才不复存在。 这就涉及到了数据持久化的问题,我们一般数据持久化的方法有,把数据存放在磁盘文件、存放到数据库等方式。


使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。


什么是文件


磁盘上的文件是文件。


但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。


程序文件


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


数据文件


文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

d14a088cbfc74a5b9f88bbb70626cf2e.png

今天讨论的是数据文件。

在以前所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显 示器上。  

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

c6d9e4816ccd4f4fb21e06ef2385eb97.png

6840f3083af343d8b3eba947fe39a997.png

文件名


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


文件名包含3部分:文件路径+文件名主干+文件后缀


例如: c:\code\test.txt


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


文件的打开和关闭


文件指针


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


每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名FILE.

c6314605c2504c9d90dd7161b1a9f1a1.png例如,VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

struct _iobuf {
  char* _ptr;
  int _cnt;
  char* _base;
  int _flag;
  int _file;
  int _charbuf;
  int _bufsiz;
  char* _tmpfname;
};
typedef struct _iobuf FILE;

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


每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息, 使用者不必关心细节。


一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。


下面我们可以创建一个FILE*的指针变量:

FILE* pf;//文件指针变量

定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变 量)。通过该文件信息区中的信息就能够访问该文件。

也就是说,通过文件指针变量能够找到与它关联的文件。

59b4887028744b42a4494c0c5a452560.png

比如:

6b8dfb8c4bd34812956ad6af91085edd.png

文件的打开和关闭

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。

在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。

ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件

44df15ef035f4352b0111dd37c0e305a.png

d48cda727d244630892b2e6296c7ceff.png

   FILE * fopen ( const char * filename, const char * mode );  


                                    文件名                            打开方式


打开方式如下:

ef873ceea3a2453a95ba54b9af80a080.png

fclose:

37a973430cda4fa49ef0a47299053727.png

  int fclose ( FILE * stream );

举个例子:

这个是绝对路径!!!

#include<stdio.h>
int main()
{
  //打开文件
  FILE* pf = fopen("test.txt", "r");
  if (pf == NULL)
  {
    perror("fopen:");
    return 1;
  }
  //写文件
  //......
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

89aa84f5570542309a1c23e6a9076d77.png

相对路径!!!

这时候,小雅兰在桌面上创建一个zyl.txl的文件,右击鼠标,点击属性,就可以看到这个文件的路径啦

5c4c3a6a1914410bb62ec03eb96610b3.png

把此位置复制粘贴到代码中

#include<stdio.h>
int main()
{
  //打开文件
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\zyl.txt", "r");
  if (pf == NULL)
  {
    perror("fopen:");
    return 1;
  }
  //写文件
  //......
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

最后就是这样,但是发现了一个问题,运行结果似乎不像我们想的那样

be51eadafa1d456e9e28165fb46f9317.png

那这又是为什么呢???

我们再次右击桌面上的那个zyl.txt文件,点击详细信息:

3dfd88f10d7643c2bf0febfec15ad671.png会发现此文件的完整名字叫zyl.txt.txt,所以,代码应该这么写:

#include<stdio.h>
int main()
{
  //打开文件
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\zyl.txt.txt", "r");
  if (pf == NULL)
  {
    perror("fopen:");
    return 1;
  }
  //写文件
  //......
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

df781c00eafc41a390247416f14d977c.png

这样就没什么问题啦!!!


文件的顺序读写

9092237e94f443b2be2ff180d381f570.png

把26个字母写到文件中:

8e4d7aff74394a57910d6e0c162d1a08.png

c6d5e693ca02415cb7431d36cce35497.png

#include<stdio.h>
int main()
{
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\yl.txt.txt", "w");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //写文件
  //把26个字母写到文件中
  int i = 0;
  for (i = 0; i < 26; i++)
  {
    fputc('a' + i, pf);
  }
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

9ce3b5cc0ff9448e8c64efbfaaff78fe.png结果竟然真的打印出来了!!!


fgetc:读文件操作

2f78436010b642afba805c1b022534c2.png

读取一个字母:

#include<stdio.h>
int main()
{
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\yl.txt.txt", "r");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //读文件
  int ch = fgetc(pf);
  printf("%c\n", ch);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

f04662272b3c4561a0e81e2dd8b4eb60.png 多读取几个字母:

#include<stdio.h>
int main()
{
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\yl.txt.txt", "r");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //读文件
  int ch = fgetc(pf);
  printf("%c\n", ch);
  ch = fgetc(pf);
  printf("%c\n", ch);
  ch = fgetc(pf);
  printf("%c\n", ch);
  ch = fgetc(pf);
  printf("%c\n", ch);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

668824af233644828d935f3e080ae758.png

那么,可不可以读取二十六个字母呢?

这当然也是可以的

#include<stdio.h>
int main()
{
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\yl.txt.txt", "r");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //读文件
  int ch = 0;
  int i = 0;
  for (i = 0; i < 26; i++)
  {
    ch = fgetc(pf);
    printf("%c ", ch);
  }
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

5e236a6318fe4fb6b5d60fdcdef3b346.png

20b8b0bf143949d5a6713e7222cf82d1.png 写一行数据 hello world                fputs

ec4fb69754314746bcf1e7224f571c62.png

49c5794ae3c64474bed20a1e95260601.png

#include<stdio.h>
int main()
{
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\yl.txt.txt", "w");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //写一行数据 hello world
  fputs("hello world\n",pf);
  fputs("hello bit\n", pf);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

862e2cb2c19d4e15b3bbabc88ac22fa0.png读一行数据:                fgets

2261340da2674ababf5418cb5081831a.png

9e8ad207b3da46448f51583d95b2e0da.png

#include<stdio.h>
int main()
{
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\yl.txt.txt", "r");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //读
  char arr[20];
  fgets(arr, 6, pf);
  printf("%s\n", arr);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

5608065f1c7e476fb91ceecef421518f.png

fprintf、fscanf——格式化地读写

fprintf——写文件

eac62175cd674852a89392a478460e53.png

对比一下参数部分:

9f63543b9f714a27b680f04f62dbc660.png

2975c833b178485785ec8b9c22d555e6.png

fb76febc785e4a3a9ae57ac56421d5e6.png

5d4f3f235b3b4a838adeabcf622de861.png

df86b263b37d448baf13de6ec2774d9a.png

45a60e1461ce4253a750f4732aee5e65.png

9aaf72d03c1b4516bfbd9f2643db586c.png

//格式化的读写
//fprintf
//fscanf
#include<stdio.h>
struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 100,3.14f,"zhangsan" };
  //打开文件
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\yl.txt.txt", "w");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //写文件
  fprintf(pf, "%d %f %s\n", s.n, s.f, s.arr);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

2fe1f696a0354d38a3362df33c0e5f37.png

fscanf——读文件

cc3eb13a22704d5186e7bce452b04012.png

同样,这个也对比一下参数部分:

d1737e40bf64470e92640d0cd8ae08f5.png

e41b1cc33ceb44e39a953877ae45ea09.png

ec5bfb7d57164fb29afc89bea8a57089.png

24212a8311bc4eae9559b17d60f96807.png

8fea81f8d0d54924a2a2db38d38a9eb6.png

e45a367455d64800973a5a429d9e0e7d.png

5d5c0951f956410f8c0e3e08caacb6e8.png

#include<stdio.h>
struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 100,3.14f,"zhangsan" };
  //打开文件
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\yl.txt.txt", "r");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //读文件
  fscanf(pf, "%d %f %s\n", &(s.n), &(s.f), s.arr);
  printf("%d %f %s\n", s.n, s.f, s.arr);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

88cb2242db7a4cf6bf5e1550b3ef9d20.png

流:

c4cf65b843f24d3e8dab37983dcb7758.png

e8b11bd558a2475a935c907a6031f67b.png

stdout、stdin、stderr都是FILE*类型的

e23d6285593a4f359376df266b9ced12.png

#include<stdio.h>
struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 100,3.666f,"hehe" };
  fprintf(stdout, "%d %f %s\n", s.n, s.f, s.arr);
  return 0;
}

4e4e8a81236f428c9a511811ea37cc3b.png

#include<stdio.h>
struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 0 };
  fscanf(stdin, "%d %f %s\n", &(s.n), &(s.f), s.arr);
  fprintf(stdout, "%d %f %s\n", s.n, s.f, s.arr);
  return 0;
}

好啦,小雅兰今天的内容就到这里啦,文件这块的知识点也是比较复杂的,有很多知识点、函数需要自己去查询,剩余内容请期待小雅兰文件(下)的博客,继续加油呀!!!

a84e0edbc53343348008d627665be2d2.jpg

相关文章
|
20天前
|
Windows
HiBit Uninstaller v3.2.10单文件版
HiBit Uninstaller是一款免费无广告功能强大的软件卸载程序,有强制卸载、批量卸载程序、Windows应用商店Appx管理器、Windows更新补丁管理器、浏览器扩展管理器、注册表清理、磁盘垃圾文件清理、快捷方式修复、文件粉碎程序、进程管理器、启动项管理器、系统服务管理器、计划任务管理器、资源管理器菜单项管理器、Windows系统还原管理器等功能。
15 2
|
21天前
|
Windows
Hasleo EasyUEFI v5.5单文件版
Hasleo EasyUEFI,轻松管理EFI/UEFI启动项 & 管理EFI系统分区 & 修复EFI系统启动问题!EasyUEFI是免费EFI启动管理软件,用于管理EFI/UEFI启动项,包括创建、删除、编辑、清理、备份和还原EFI/UEFI启动项。
14 0
|
2月前
|
存储 内存技术
什么是文件
什么是文件
14 0
|
8月前
|
NoSQL Python
PythonExcel文件
在Python中,我们可以使用许多库来处理Excel文件,其中最常用的是pandas和openpyxl。
|
存储 C语言
文件(下)——“C”
文件(下)——“C”
|
C语言
文件二合一
通过对C语言二进制文件的操作,将两个文件合并成为一个新的文件。通过改后缀的方式使的文件自由转换。
43 0
|
存储
Fasta和Fastq文件
Fasta和Fastq文件
177 0
|
Go 数据安全/隐私保护 Windows
WinNTSetup V5.3.0 Bata5 单文件版
WinNTSetup 是一款Windows系统硬盘安装器,支持从PE和本地安装系统,支持支持NT内核的系统。
WinNTSetup V5.3.0 Bata5 单文件版
文件的使用详解
👩‍💻博客主页:[风起 风落](https://blog.csdn.net/qq_62939852?spm=1001.2101.3001.5343)的博客主页 ✨欢迎关注🖱点赞🎀收藏⭐留言✒ 👕参考网站:牛客网 💻首发时间:🎞2022年7月30日🎠 🎨你的收入跟你的不可替代成正比 🀄如果觉得博主的文章还不错的话,请三连支持一下博主哦 💬给大家介绍一个求职刷题收割offer的地方👉[点击网站](https://www.nowcoder.com/link/pc_csdncpt_fqfl_c)
108 0
文件的使用详解