c语言学习第三十三课——文件

简介: c语言学习第三十三课——文件

注意以下文件操作中,文件均已创建

1.为什么使用文件

程序运行时的读写的数据保存在内存里,一旦小程序结束,数据会被回收。若有文件,程序在运行时,信息储存在内存中,从内存中读取数据并把数据保存到磁盘上,即数据保存到文件中,可持久保存下来。

2.什么是文件

磁盘上的文件就是文件。

文件分为两种 程序文件(包括源文件,目标文件,exe可执行程序)与数据文件(文件的内容,程序运行时从中读取或输出的内容)(从文件功能分类)

本次讨论数据文件

文件名:一个文件要有一个唯一的文件标识,以便用户识别引用,文件路径+文件名主干+文件后缀

3.文件的打开与关闭

文件的操作:

1.文件打开      2.文件操作(读写)      3.文件关闭

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

每一个被使用的文件都会在内存中开辟了一个对应的信息区,用来存放文件信息(包括文件名,文件内容等)。

可理解为创建了一个文件指针型的结构体变量,该信息就保存在结构体变量中。该类型指针也会维护该信息区

不同的c编译器对FILE类型包括的内容大同小异。

创建FILE型的指针变量FILE*fp;

打开与关闭

文件信息区规定使用fopen与fcloae来打开与关闭文件。

文件使用方式

文件打开fopen

6f585911111047778f579cad483fe37d.png

函数参数为(文件名,文件打开方式),返回类型为文件指针型,也是流。

在C语言中文件打开方式有这么几种:

r :以只读方式打开文件,只能读不能写,往文件中写是没有任何效果的。

r+ :可以读,也可以写,文件打开的时候,指向文件开头,可以通过seek改变读写位置。

w :建立供写入的文件,这种方式打开的文件句柄,只能写,如果文件存在则将长度清零,否则新建文件。

w+ :建立用于更新数据文件,如果已存在就抹去原有数据。同w选项,只不过多了一个可读功能;

a :打开或建立一个把数据追加到文件尾的文件。

a+ :同a选项,多了可读的功能。

fclose文件关闭

1d9a9060709b49efb64efb5d10db1359.png关闭文件,参数为文件型指针,返回类型为整形,返回成功return 0,否则返回EOF(-1).

这里还需注意,在完成关闭文件后,需要对文件指针置空,否则该指针就是一个野指针。

举一个文件打开与关闭的实例

#include<stdio.h>
int main()
{
  //相对路径
  FILE* fp = fopen("text.txt","w");//w打开会清清除原文件的内容
  //绝对路径
  //整个文件的路径
  //FILE*fp=fopen("c:\\user\\.....text,txt","w")
  if (fp == NULL)
  {
    perror("fopen");
    return 1;
  }
  //写文件
  //关闭文件
  fclose(fp);
  fp = NULL;//指针置空,防止为野指针
  return 0;
}

在打开文件还需要注意的一点是,所打开的文件的文件名的路径的区别。所谓相对路径,即该文件是放在该源码文件底下的,打开文件时只用书写文件名,程序运行时直接访问,而绝对路径即他的整个路径,你放在哪里,文件打开就打开哪里的文件,不过路径是完整的。

还需要注意一点如果是绝对路径,注意拷贝来的地址是由转义字符的,在转义字符处加上\,取消转义。才能正确访问该路径。

4.文件的顺序读写

文件的读取输出函数有许多,这里介绍几个。

f163870cbd5b498e9a72e63acc5c28f1.png

写字符函数fputc

be13f293283d43f5b317fea45642628a.png 函数参数为(写入的字符,文件指针),返回类型为

这里注意,每执行一次fputc函数,指针所指向的位置就会往后移动,即再次执行就会直接把写入的下一个字符写到文件里。

读入字符函数 fgetc

aecec2db29c14d0a90211dcd91ecfc93.png

c963b21c81d74a22be9c0acf8856ff16.png

可以发现该函数返回的是读取字符的ASCLL码值,参数为文件指针变量。

int main()
{
  FILE* pf = fopen("text.txt","w");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //写文件
  //把二十六个字母写到文件中
  for (int i = 0; i < 26; i++)
  {
    fputc('a' + i, pf);
  }
  //读文件
  //文件末尾隐藏EOF
  int ch = fgetc(pf);//返回ASCLL码值  一次读一个字符
  for (int i = 0; i < 26; i++)
  {
    fgetc(pf);
  }
  //读取失败会返回EOF
  printf("%c", ch);
  fclose(pf);
  pf = NULL;
}

这里举例写入26个字符到文件中,再读取该26个字母到文件中。这里注意的是,函数将文件里的结束标志默认为EOF,遇到EOF函数就会返回。

fscanf  格式化读

de08819639a44ef1b0e19230037374d8.png

这里的函数明显看到与上面两个存在区别,首先操作对象是字符串了,其次函数参数里...的这个表示可变参数,即这里的读取数据的参数可以不止一个,这里我将会用结构体举例。

函数参数为(文件指针,读数据的方式,数据)。

fprintf  格式化写

dbabdef13f574299bef7ff5a98899f07.png

这里fprintf函数写数据到文件中,图片阐述的清晰,不做赘述。但要注意的是这里的函数但数为

(文件指针,写入文件数据的方式,数据的地址) 。

具体见实例:

struct S
{
  int n;
  float f;
  char arr[20];
};
int amin()
{
  struct S s = { 100,3.14f,"hello" };
  FILE* p = fopen("text,txt", "w");
  if (p == NULL)
  {
    perror("fclose");
    return 1;
  }
  //写
  fprintf(p, "%d %f %s", s.n, s.f, s.arr);
  return 0;
}
int amin()
{
  struct S s = { 0 };
  FILE* p = fopen("text,txt", "r");
  if (p == NULL)
  {
    perror("fclose");
    return 1;
  }
  //读
  fscanf(p,"%d %f %s",&(s.n),&(s.f),&s.arr);//读取文件内容,存放到结构体里
  printf("%d %f %s", s.n, s.f, s.arr); 
  return 0;
}

以上的函数从刚开始的图片就可以看到标志了他们的输入输出都是所有输入流或所有输出流。

那什么是流呢?

流的概念

流就可想象成水流,可拿可放 ,而 把数据写在文件中,  也可以拿出数据从文件中  , 写入与拿出就像水流一样,既可以流进来,也可以放出去。

假设向文件里写数据  ,向终端里写数据(屏幕),向网络里写数据,向软盘里写数据,外部设备里写数据,,,取图:


eca8e2dae38a4600a30b136ec7729ac0.png

把数据 通过一种方式写进这些  设备等,即我们可以抽象的理解数据写到流里面,而流有自己的方式如何把数据写进哪里,如何去写,我们只需负责数据对流的输入,或输出,即写与读。、

由于流的对象有多种,我们把他们这样认识

写文件时候:称作文件流

终端设备-屏幕:标准输出流  stdout

键盘:标准输入流            stdin

屏幕:标准错误流           stderr

一个c语言程序默认会打开三个流(stdout stdin stderr)

而 以上函数是所有的输入流或输出流,因此我们读写数据的方式也可以这样来:

fgetc 从标准输出流读取数据。

int main()
{
  //stdin  stdout  stderr 都是FILE *类型的
  int ch = fgetc(stdin);
  printf("%c\n", ch);//从屏幕读入数据,并打印
}

fputc 从标准输入流输入数据。

int main()
{
  fputc('a', stdout);//从屏幕输出字符a
  fputc('b', stdout);//从屏幕输出字符b
  fputc('b', stdout);//从屏幕输出字符c
  fputc('d', stdout);//从屏幕输出字符d
}

fprintf 从标准输入流输入数据。

struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 100, 3.666, "hehe" };
  fprintf(stdout, "%d %f %s", s.n, s.f, s.arr);//读取数据输出到屏幕上
}

fgets从标准输出流读取数据。

int main()
{
  struct S s = { 0 };
  fscanf(stdin, "%d %f %s", &s.n, &s.f, s.arr);//输入数据到屏幕上并赋值给结构体成员
  fprintf(stdout, "%d %f %s", s.n, s.f, s.arr);//读取数据输出到屏幕上
  return 0;
}

其外还有一组函数sprintf与sscanf;

sprintf 格式化数据转化为字符串

065b200063af411ca9efc737c0770448.png

sscanf 将字符串转化为格式化数据

b5db936c7821498d8d84039ba6a380b4.png

struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 200,3.5f,"hello" };
  //把结构体变成字符串
  char arr[200] = { 0 };
  sprintf(arr, " %d %f %s",s.n, s.f, s.arr);
  printf("%s\n",arr);
  //把一个字符串转换成格式化数据
  struct S tmp = { 0 };
  sscanf(arr, "%d %f %s", &(tmp.n), &(tmp.f), tmp.arr);
  printf("%d %f %s", tmp.n, tmp.f, tmp.arr);
  return 0;
}

三组函数对比

了解完后我们来对比三组函数

对比一组函数

输入函数

 scanf   针对标准输入流的  stdin    

fscanf  针对所有的输入流(文件流 stdin 等)  

 sprintf   把一个格式化的数据转化成字符串    

对比输出函数                  

   print      针对标准输出流     stdout    

fprintf(针对所有输出流)(文件流 stdout  等)

sscanf    把字符串转换为格式化数据


相关文章
|
1月前
|
存储 编译器 C语言
如何在 C 语言中判断文件缓冲区是否需要刷新?
在C语言中,可以通过检查文件流的内部状态或使用`fflush`函数尝试刷新缓冲区来判断文件缓冲区是否需要刷新。通常,当缓冲区满、遇到换行符或显式调用`fflush`时,缓冲区会自动刷新。
|
1月前
|
存储 编译器 C语言
C语言:文件缓冲区刷新方式有几种
C语言中文件缓冲区的刷新方式主要包括三种:自动刷新(如遇到换行符或缓冲区满)、显式调用 fflush() 函数强制刷新、以及关闭文件时自动刷新。这些方法确保数据及时写入文件。
|
1月前
|
C语言
【C语言】探索文件读写函数的全貌(三)
【C语言】探索文件读写函数的全貌
|
1月前
|
存储 C语言
【C语言】探索文件读写函数的全貌(二)
【C语言】探索文件读写函数的全貌
|
1月前
|
C语言
教你快速理解学习C语言的循环与分支
教你快速理解学习C语言的循环与分支
17 0
|
1月前
|
C语言
【C语言】探索文件读写函数的全貌(一)
【C语言】探索文件读写函数的全貌
|
1月前
|
存储 文件存储 C语言
【C语言】深入了解文件:简明指南
【C语言】深入了解文件:简明指南
|
2月前
|
Linux C语言
C语言 文件IO (系统调用)
本文介绍了Linux系统调用中的文件I/O操作,包括文件描述符、`open`、`read`、`write`、`lseek`、`close`、`dup`、`dup2`等函数,以及如何获取文件属性信息(`stat`)、用户信息(`getpwuid`)和组信息(`getgrgid`)。此外还介绍了目录操作函数如`opendir`、`readdir`、`rewinddir`和`closedir`,并提供了相关示例代码。系统调用直接与内核交互,没有缓冲机制,效率相对较低,但实时性更高。
|
3月前
|
存储 C语言
【C语言】C语言-学生成绩管理系统(源码+数据文件+课程论文)【独一无二】
【C语言】C语言-学生成绩管理系统(源码+数据文件+课程论文)【独一无二】
56 15
|
3月前
|
存储 C语言
【c语言】职工信息管理系统 包含读取写入txt文件,职工信息的增删改查
【c语言】职工信息管理系统 包含读取写入txt文件,职工信息的增删改查