C语言进阶第十课 --------文件的操作-1

简介: C语言进阶第十课 --------文件的操作

使用文件的意义

前面我们写过很多的代码,运行了很多的程序,但是一旦程序结束了或者断电了,这数据就会不见了,因为这些数据是存储在内存中的,但是使用文件可以有效防止

文件是存在硬盘的


什么是文件

在程序设计中,我们一般谈论两种:一种是程序文件,另一种是数据文件


程序文件

包含有源程序文件(如.c)、目标文件(.obj)、 可执行文件(.exe)


数据文件

数据文件就是被读取数据或者写入数据的文件,或者我们可以理解为我们操作哪个文件哪个文件就是数据文件


操作对象

前面我们使用scanf和printf所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显

示器上。

52518e935babec99b2a3a6a14f5d8c7a_2cd92391f16e49b089c9483eae46aae4.png

现在我们把键盘和屏幕换成了文件,输入就是读取文件内容, 输出就是往文件里面写入数据,

ba9b607fe0beb3862c63aacdd56cba52_022b9f01a0a245dabaf3154812d6c2d7.png

这里的程序中的数据是保存在内存中的


文件名

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

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

例如: C:\a\b.c

C:\a\是文件路径 ,b是文件主干 .c是文件后缀


文件的打开和关闭

文件指针

C语言中每个文件的使用都会在内存开辟一块空间,也就是文件信息区,用来存放文件的相关信息,这些信息是保存在一个名叫FILE类型的结构体变量中,这个FILE是一个结构体类型


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类型的结构体变量的地址


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

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


b8221663b789c80e4586e0cd10c14843_f9cab1fc6bc3408fa61d76f9395e08d1.png

那我们怎么找到这个变量的地址呢?,当我们打开一个文件的时候就会创建一个文件信息区,并且自动填充相关信息


文件的打开和关闭

打开

1cf2690ec3e22ab0d75d1650754436ad_43490c5cb4dd4b4281a2ef63cbcda7d8.png

fopen 函数返回一个指向 FILE 结构体的指针,该结构体用于表示打开的文件。如果打开文件失败,函数将返回 NULL。在使用完打开的文件后,应该使用 fclose 函数关闭文件

filename:文件名

mode:打开方式

这两个参数只需我们传入两个字符串常量就可以,传入字符串常量就会把第一个字符的地址传入进去

打开方式如下:

2f3f49c36fcb9f8b3ce5b9e6d81ba6b8_b48b1aaa1eb040e6848909e6a7b02914.png


关闭

764b81a403ac61fe7a2f1ed647f25029_589edbb8c7124c428a95fca8fe5157f7.png

需要注意的是,fclose 函数将文件缓冲区中的数据写入磁盘,并释放与该文件相关的所有资源。在关闭文件之前,应该确保已完成对文件的所有操作。

如果流成功关闭,则返回零值。

失败时,将返回 EOF。


#include<stdio.h>
int main()
{
  FILE *p = fopen("./test.txt", "w");
  if (p == NULL)
  {
    perror("fopen");
    return 1;
  }
  int b = fclose(p);
  printf("%d", b);
  p = NULL;
  return 0;
}

文件的顺序读写

前面我们使用scanf和printf是在终端操作的,如果我们要在文件上操作就不能使用这些函数

我们要站在内存的角度思考,写入内存的数据叫输入,从内存中输出数据叫输出

7c887387b1b3b5d06ad0094f1e9687f9_e4c116e125e446b8a8b967d9f4f8c432.png

这个图是一个简便的,文件到程序和文件到程序都不是一步到位的,都要经过一个流,

cc533542f0cabdb3885fbb0fb6ff2ace_41ea368fcfc0454eb0a07e9d202ead2a.png

本质上我们是操作流来操作文件,我们使用scanf和printf可以直接操作数据,是因为,C语言程序只要运行起来就会打开三个流 :标准输入流(stdin) 、标准输出流(stdout)、 标准错误流(stderr)

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


输出流(把数据写入到流,而不是写入到文件)(对象是屏幕):


#include<stdio.h>
#include<stdlib.h>
int main()
{
  //打开文件
  FILE* file = fopen("./test.txt", "w");
  if (file == NULL)
  {
    perror("fopen");
    return 1;
  }
  char str;
  int a = 0;
  while ( a < 10)
  {
    scanf("%c", &str);
    getchar();
    fputc(str, stdout);
    a++;
  }
  
  fclose(file);
  file = NULL;
  return 0;
}

输入流(从流中获取数据,而不是从文件里面获取)(对象是键盘):

#include<stdio.h>
#include<stdlib.h>
int main()
{
  //打开文件
  FILE* file = fopen("./test.txt", "w");
  if (file == NULL)
  {
    perror("fopen");
    return 1;
  }
  char str;
  
  str = fgetc(stdin);
  printf("%c", str);
  fclose(file);
  file = NULL;
  return 0;
}

文件流:文件变量的地址,也就是fopen返回的地址


字符输出函数

bbfc8230bd03870471dc46cb37f75694_94f8306a89f7449b92dce8012f9d3838.png

fputc 函数将字符写入文件后,文件指针会自动向后移动一个字符位置。如果写入成功,函数将返回写入的字符;否则,返回 EOF。


#include<stdio.h>
#include<stdlib.h>
int main()
{
  //打开文件
  FILE* file = fopen("./test.txt", "w");
  if (file == NULL)
  {
    perror("fopen");
    return 1;
  }
  char str;
  int a = 0;
  while ( a < 10)
  {
    scanf("%c", &str);
    getchar();
    fputc(str, file);
    a++;
  }
  
  fclose(file);
  file = NULL;
  return 0;
}

字符输入函数

bcc1eb0d5529d85ea6977b389c3c4814_03327a75553642629c3728244b5a31be.png

stream是一个指向文件的指针,指向我们要读取的文件流。函数返回值是读取的字符的ASCII码值,如果到达文件末尾或者读取出错,返回EOF。


#include<stdio.h>
#include<stdlib.h>
int main()
{
  FILE* file = fopen("./test.txt", "r");
  if (file == NULL)
  {
    perror("fopen");
    return 1;
  }
  char a;
  int b = 0;
  while (b < 5)
  {
    a = fgetc(file);
    printf("%c ", a);
    b++;
  }
  fclose(file);
  file = NULL;
  return 0;
}

文本字符串输出函数

09e940a2dbdf10febef3fb2d17f12303_55f5dd05d11d45659ea6c4849bd99212.png

,str是要写入的字符串,stream是一个指向文件的指针,指向我们要写入的文件流。函数返回值为非负整数表示成功,如果写入出错,返回EOF。


#include<stdio.h>
#include<stdlib.h>
int main()
{
  FILE* file = fopen("./test.txt", "w");
  if (file == NULL)
  {
    perror("fopen");
    return 1;
  }
  char arr[30] = "qwertytuio";
  int a = fputs(arr, file);
  printf("%d", a);
  fclose(file);
  file = NULL;
  return 0;
}

文本字符串输入函数

c809bcb06c996e32cfac0503b8bb7589_07cab1c7552e433c888f50972ba77acd.png

str是一个指向字符数组的指针,用于存储读取到的字符串;n是要读取的最大字符数(包括空字符);stream是一个指向文件的指针,指向我们要读取的文件流。函数返回值是一个指向存储读取到的字符串的指针,如果到达文件末尾或者读取出错,返回NULL。

需要注意的是在文件中真正读取的字符是 n - 1,或者读取到\n或者读完文件内容就不会继续读下去


#include<stdio.h>
#include<stdlib.h>
int main()
{
  FILE* file = fopen("./test.txt", "r");
  if (file == NULL)
  {
    perror("fopen");
    return 1;
  }
  char arr[20];
  fgets(arr, 5, file);
  printf(arr);
  fclose(file);
  file = NULL;
  return 0;
}

格式化输出函数

47af18c4392d870311ff8dd4b40f472d_921a6ee0d9a047f6a94464a682843a39.png

如果我们对比printf函数就会发现.fprintf多了stream这个参数,

stream是一个指向文件的指针,指向我们要写入的文件流;format是一个格式化字符串,用于指定写入数据的格式;…表示可变参数,用于提供要写入的具体数据。


成功后,将返回写入的字符总数。

如果发生写入错误,则设置错误指示器(ferror)并返回负数。

如果在写入宽字符时发生多字节字符编码错误,errno 将设置为 EILSEQ 并返回负数。


#include<stdio.h>
#include<stdlib.h>
int main()
{
  FILE* file = fopen("./test.txt", "w+");
  if (file == NULL)
  {
    perror("fopen");
    return 1;
  }
  fprintf(file, "%d\n", 123456789);
  char arr[11];
  fclose(file);
  file = NULL;
  //光标回复
  FILE* file1 = fopen("./test.txt", "r");
  if (file1 == NULL)
  {
    perror("fopen");
    return 1;
  }
  fgets(arr, 10, file1);
  printf(arr);
  fclose(file1);
  file1 = NULL;
  return 0;
}

格式化输入函数

371f031abcad6148cea4703f67a8087d_12219e3352a0439a85f160656e8ff8fa.png

如果和scanf函数对比就会发现fscanf只是多了stream参数

stream 是指向要读取的文件的指针,format 是格式字符串,用于指定要读取的数据类型和格式。


成功后,该函数返回成功填充的参数列表的项数。此计数可以与预期的项目数匹配,也可以由于匹配失败、读取错误或文件末尾的到达而减少(甚至为零)。

如果发生读取错误或在读取时到达文件末尾,则会设置正确的指示器(feof 或 ferror)。并且,如果在成功读取任何数据之前发生任一情况,则返回 EOF。

如果在解释宽字符时发生编码错误,该函数会将 errno 设置为 EILSEQ。


#include<stdio.h>
#include<stdlib.h>
int main()
{
  FILE* file = fopen("./test.txt", "r");
  if (file == NULL)
  {
    perror("fopen");
    return 1;
  }
  int a;
  fscanf(file, "%d", &a);
  printf("%d", a);
  fclose(file);
  file = NULL;
  file = fopen("./test.txt", "w");
  if (file == NULL)
  {
    perror("fopen");
    return 1;
  }
  fprintf(file, "%d", 11111111);
  fclose(file);
  file = NULL;
  return 0;
}


C语言进阶第十课 --------文件的操作-2

https://developer.aliyun.com/article/1498899

相关文章
|
1天前
|
存储 程序员 C语言
C语言:文件操作
C语言:文件操作
11 1
|
1天前
|
存储 C语言 C++
【C语言】文件与文件操作
前言:我们通过学习的技术可以完成计算与字符串处理,但程序结束之后就都消失了,这样岂不可惜。我们通过文件与数据持久化保存相关的基础知识。
10 0
|
1天前
|
存储 编译器 C语言
C语言中的文件操作指南
C语言中的文件操作指南
14 0
|
1天前
|
算法 C语言
【C 言专栏】C 语言文件操作的技巧与方法
【4月更文挑战第30天】本文介绍了C语言文件操作的关键技巧,包括文件的打开与关闭(使用`fopen`和`fclose`函数),读取(`fgetc`、`fgets`和`fread`)和写入(`fputc`、`fputs`和`fwrite`)操作。此外,还讨论了文件指针移动(`fseek`)、错误处理、文件权限和格式等问题。文中提供了一个简单的读写文件的示例,并提到了高级技巧如随机访问、文件缓冲和截断。掌握这些技能将有助于提升C语言编程中的文件处理能力。
|
1天前
|
存储 C语言
C语言进阶---------作业复习
C语言进阶---------作业复习
|
1天前
|
存储 Linux C语言
C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)-2
C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)
|
1天前
|
自然语言处理 Linux 编译器
C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)-1
C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)
|
1天前
|
存储 C语言
C语言进阶第十课 --------文件的操作-2
C语言进阶第十课 --------文件的操作
|
1天前
|
存储 程序员 C语言
C语言进阶第九课 --------动态内存管理-2
C语言进阶第九课 --------动态内存管理
|
1天前
|
编译器 C语言
C语言进阶第九课 --------动态内存管理-1
C语言进阶第九课 --------动态内存管理