超详细的文件操作讲解

简介: 各位朋友们,大家好啊,今天我要分享的是关于文件操作方面的知识。

为什么会有文件操作


那么大家可能会问:为什么会有文件操作呢?前面我们可能都了解了通讯录,我们知道当我们使用通讯录的时候我们可以添加联系人,也可以删除联系人,但是当我们退出程序之后下次再进来的时候,我们要想看看通讯录里面有那些联系人,我们打开通讯录发现里面是空的,这是为什么呢?因为我们这种通讯录实在内存上操作的,当我们关闭程序或者关机的时候,这些内存就会被释放掉了,那么我们想要下次打开通讯录的时候,里面的内容还在的话,我们就需要使用文件来操作了。


什么是文件


文件通常是指磁盘上的文件,就像我们平时购买电脑的时候我们可能会买16+512的,这个16通常是指运行内存,我们写代码的时候通常使用的就是这个内存,而我们安装QQ、微信啊这些就是安装在磁盘上的,这些数据不会随着你电脑关机或者没电的时候而消失,他会一直存在,除非你故意删除或者磁盘损坏。所以我们使用文件来操作可以将数据存储在磁盘上保存。


文件又分为程序文件文件和内存文件。他们分类的依据是根据功能来分类的,不知道你们是否发现了,当我们写了一个代码并编译运行的时候,我们可以在我们项目的文件路径下发现.obj后缀和.exe后缀的文件,这些等等都属于程序文件,而当我们程序运行的时候读取的文件称为数据文件。


那么我们知道了什么是文件以及使用文件的好处了之后,我们来学习怎样进行文件操作。


文件操作


文件指针


每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名FILE。也就是说我们需要使用FILE来找到文件的地址,并对其进行相关操作。其实这就跟普通指针差不多,就像int* p = &a,一样*说明他是一个指针变量,而int说明这个指针指向的是int类型的数据,FILE也是如此。


文件的打开与关闭


当我们使用文件的时候我们需要在知道使用的步骤,就像我们想要在冰箱里面拿东西一样,我们首先需要打开冰箱,然后我们可以从冰箱里面拿出东西也可以往冰箱里面放东西,我们进行文件操作的时候也是先打开文件,然后进行相关操作,最后就是关闭文件。


fopen(打开文件)

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

const char* filename是我们要打开的文件地址,const char* mode是我们以怎样的形式打开。


fclose(关闭文件)

int fclose ( FILE * stream );

FILE * stream是我们需要关闭的文件地址,这里我们需要注意的是fclose并不会将要关闭的文件置为NULL,所以我们需要手动置空。


接下来我们就来看看有哪些打开文件的方式吧。


打开文件的方式


image.png


我们在使用的时候可以根据需要以不同的方式打开。我们举个例子:

首先我们在我们的项目路径下创建一个test.txt文档,用来做测试。


7.png


然后我们在这个文档里面写入内容。


8.png

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

image.png


我们这里就是以读的形式打开的。


文件的顺序读写


image.png


这里的流是什么意思呢?其实这个流只是一个抽象概念,就像一条河流,当我们需要灌溉农田的时候我们就可以用抽水机来抽取。我们的键盘和屏幕实际上也是一个文件,我们的电脑从键盘中读取数据,然后将数据显示到屏幕上,键盘也叫标准输入流(stdin),屏幕叫做标准输出流(stdout)。


那么我们来举几个例子来看看这写函数是什么作用吧。


fgets函数

char * fgets ( char * str, int num, FILE * stream );
#include<stdio.h>
int main()
{
  //打开文件
  FILE* pf = fopen("test.txt", "r");
  char arr[10] = { 0 };
  if (pf == NULL)
  {
    perror("fopen");
    return 0;
  }
  //进行相关文件操作
  fgets(arr, 5, pf);
  printf("%s", arr);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

11.png


虽然我们在这里想要读取5个元素,但是其实只读取了4个元素,因为最后一个元素要读取’\0’。


fputc函数

int fputs ( const char * str, FILE * stream );

我们先将前面的文档里面的内容删除。

12.png

#include<stdio.h>
int main()
{
  FILE* pf = fopen("test.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;
}

image.png

fgets函数

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

fgets可以读取一行的数据

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

image.png


fputs函数

fputs写一行的数据

int fputs ( const char * str, FILE * stream );
#include<stdio.h>
int main()
{
  FILE* pf = fopen("test.txt", "w");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  fputs("hello bit", pf);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

15.png

fprintf函数

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

后面的省略号说明你自己可以定义长度。

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

image.png


fscanf函数

int fscanf ( FILE * stream, const char * format, ... );
#include<stdio.h>
struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = {0};
  //打开文件
  FILE* pf = fopen("test.txt", "r");
  if (NULL == pf)
  {
    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;
}

image.png


那么前面的都是顺序读写,但是当我们想要在任意位置写的时候我们又该怎么办呢?

我们这就得用到fseek函数和ftell函数了,这两个函数可以随机读写文件。


文件的非顺序读写

fseek函数

int fseek ( FILE * stream, long int offset, int origin );

stram还是我们需要读取的文件的地址,offset 是相对于origin的偏移量,origin有三种不同的形式。SET表示文件的开始位置,CUR表示文件指针的当前位置,END表示文件的结尾。


18.png

19.png

#include<stdio.h>
int main()
{
  FILE* pf = fopen("test.txt", "r");
  if (pf == NULL)
  {
    perror("fopen file");
    return 1;
  }
  for (int i = 0; i < 5; i++)
  {
    fgetc(pf);
  }
  //现在pf文件指针已经向后移动了5个字节,现在我们想要读取的元素是b,b与文件首元素的地址的偏移量是1
  fseek(pf, 1, SEEK_SET);
  int a = fgetc(pf);
  printf("%c", a);
  fclose(pf);
  pf = NULL;
  return 0;
}

20.png

ftell函数

long int ftell ( FILE * stream );

ftell函数返回的是你当前的文件指针与文件开始的地址处的偏移量,这里我就不需要过多解释了。


rewind函数

void rewind ( FILE * stream );

这个函数的作用是让文件指针回到文件的起始位置


二进制读写


fwrite函数`

fwrite函数是针对二进制来说的,他写入的形式是以二进制来写的。

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

这个函数返回的是你写入的字符的个数,参数一个是ptr,代表的是从哪写入,一个是size,表明要写入的内容的大小,count是指要写入多少个这样的内容,stream是你要写入那个文件中。

#include<stdio.h>
struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 10,3.14f,"hello" };
  FILE* pf = fopen("test.txt", "wb");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  fwrite(&s, sizeof(struct S), 1, pf);
  fclose(pf);
  pf = NULL;
  return 0;
}

21.png


这样我们可能看不懂吧,因为这是以二进制的形式写入的,所以我们并不能看懂。


fread函数

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
#include <stdio.h>
struct S
{
  char name[20];
  int age;
  float score;
};
int main()
{
  struct S s = {0};
  FILE* pf = fopen("test.txt", "rb");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //读文件
  fread(&s, sizeof(struct S), 1, pf);
  printf("%s %d %f\n", s.name, s.age, s.score);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}


image.png


结语


那么这些就是我学到的关于文件操作的只是,感谢大家的观看,如有错误,请随时订正。


相关文章
|
存储 C语言 Windows
文件操作(上)
文件操作(上)
51 0
|
5月前
|
存储 C++
C++文件操作
C++文件操作
|
6月前
|
C语言
文件操作(2)
文件操作(2)
43 3
|
6月前
|
存储 程序员 编译器
文件操作(1)
文件操作(1)
47 2
|
5月前
|
存储 程序员 编译器
文件操作详解
文件操作详解
59 0
|
程序员 C语言 Windows
【文件操作】
【文件操作】
45 0
|
6月前
|
C++
轻松学会文件操作(2)
轻松学会文件操作(2)
|
6月前
|
存储 程序员 编译器
|
6月前
|
存储 Java C语言
文件操作你会了吗
文件操作你会了吗
79 0
|
程序员 编译器 C语言
文件操作(中)
文件操作(中)
36 0