进阶C语言 第六章-------《文件操作》 (fgetc、fputc、fgets、fputs、fprintf、fscanf)知识点+完整思维导图+基本练习题+深入细节+通俗易懂建议收藏(二)

简介: 进阶C语言 第六章-------《文件操作》 (fgetc、fputc、fgets、fputs、fprintf、fscanf)知识点+完整思维导图+基本练习题+深入细节+通俗易懂建议收藏(二)

4.文件的顺序读取

4.1顺序读取函数

知识点:        

输出:内存中输出到文件中/屏幕中(put,write、prinf)

fprintf从指定格式的数据内存得到数据输出到文件里、printf从指定格式的数据内存得到数据输出在屏幕上,

输入:从键盘/文件中读取到输入到内存中(read、get、scanf)

fscanf从文件得到输入到指定内存再进行printf,scanf从键盘上得到输入在指定内存

image.png

头文件都一样是#include<stdio.h>

功能 函数名          适用于
字符输入函数 int fgetc ( FILE * stream ); 所有输入流
字符输出函数 int fputc(int character,FILE * stream) 所有输出流
文本行的输入函数 char * fgets ( char * str, int num, FILE * stream ); 所以输入流
文本行的输出函数 int fputs ( const char * str, FILE * stream ); 所有输出流
格式化输入函数 int fscanf ( FILE * stream, const char * format, ... );  所有输入流
格式化输出函数 int fprintf ( FILE * stream, const char * format, ... ); 所有输出流
二进制输入函数 size_t fread ( void * ptr, size_t size, size_t count, FILE * stream ); 文件
二进制输出函数 size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream ); 文件

附:

流(stream):

当我们在写代码时,我们只需要把代码通过函数写好后在流中就可以实现我们需要的结果,这是因为C语言已经封装好的程序(流),一般来说当运行一个C语言程序时会自动打开

3个流(这也对应这scanf、printf、perror):

stdin   - 标准输入(键盘)         类型      FILE *

stdout - 标准输出(屏幕)                      FLIE *

stderr -  标准错误(屏幕)                      FLIE *

image.png

所以我们在每次写程序控制文件的时候就必须先打开文件也就拥有指向这个文件的流

才能进行文件的输入(文件的打开方式"r",就对应像stdin的这样的输入流)、输出(打开文件的方式"w",对应输出流);所以上面的前6个里他们适合所有输入/输出流也就表明了,他们既可以对文件流中使用,也可以在标准流中使用

具体如下:

标准流时:

#include<stdio.h>
int main()
{
  int ch = fgetc(stdin);
  fputc(ch,stdout);
  return 0;
}

image.png

image.png

细节:

文件流时:

4.1.1.fgetc、fputc

他们返回的都是整形也就是字符所对应的ASCII码值  

int fgetc ( FILE * stream ) ;             int fputc(int character,FILE * stream);

而他们的参数 FILE * stream 是指对应文件信息区的地址、int character 是所要写的字符的ASCII码值(直接传字符进去进去后都会转成ASCII码值)

练习:

将a~z的英文字母存放在文件中,并读取后打印

 #define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
    FILE* pf = fopen("test.txt", "w");//同过写的方式来打开文件,在每次写的时候都相当于重新创建一个文件,将原文件数据覆盖
    if (pf == NULL)//防止开辟失败,访问NULL
    {
        perror("fopen");
        return 1;
    }
    //使用文件 此处省略
    for (int i = 'a'; i <= 'z';i++)
    {
        fputc(i, pf);
    }
    //关闭文件
    fclose(pf);
    pf = NULL;
    FILE* pf1 = fopen("test.txt", "r");//通过读的方式来读取数据
    if (pf1== NULL)//防止开辟失败,访问NULL
    {
        perror("fopen");
        return 1;
    }
    //使用文件 此处省略
    for (int i = 'a'; i <= 'z'; i++)
    {
        int ch = fgetc(pf1);//返回ASCII码值并打印
        printf("%c ", ch);
    }
    //关闭文件
    fclose(pf1);
    pf1 = NULL;
    return 0;
}

image.png

对于fgetc来说他会按顺序一个个读取,先读最前面的读完后会自动指向下一个,当下一次再次读取时就会接着读下一个的了;对于fputc来说同样的他会一个个写,写完后自动往下指继续写,但假如重新打开文件(以写的方式)就会被覆盖。

如果读取失败/或写入失败的话将会返回EOF

4.1.2.fgets、fputs

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

他读取在stream中指定num个字符放在str中,若成功返回时返回:str、若失败了则返回EOF

参数 str 表示的是所要存/所要取字符串的位置的地址

参数 num 表示的是所要得到的字符的(num-1)个,为什么是num-1个是因为在读时字符串的最后要放上一个\0,所以会占掉一个位置;并且当遇到\n时会自动停止并且把\n换成\0,并且假如num的大小大于所要读大小会将多余的位置置为\0

参数 stream 表示的是文件信息区的地址

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

他把str指向的字符串放到stream文件信息区上成功返回时返回:非负数;若失败了则返回EOF

这个就相对简单了就是将字符串的首地址传进去,以及文件信息区的位置

一行行的写,每一次写一行

int main()
{
  FILE* pf = fopen("test.txt","w");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  fputs("hello world\n", pf);//文件输出函数
  fputs("hello bit\n", pf);
  fclose(pf);
  pf = NULL;
  FILE* pf1 = fopen("test.txt", "r");
  if (pf1 == NULL)
  {
    perror("fopen");
    return 1;
  }
  char ch[20] = { 0 };//
  fgets(ch,12,pf1);//文件输入读取,并且此时字符串时12个字符那么就需要13个空间,因为fgets会在最后加上一个\0(但是此处只会那取 12 - 1 个字符 在最后12的位置要放上\0 )
  printf("%s", ch);//hello world
  fgets(ch, 10, pf1);
//此处因为一开始将前面的11(num - 1)个字符读去了在第一行还剩下一个\n所以就会把\n读取到,并且fgets遇到\n会自动停止并且将\n换成\0,并且因为只读一行所以会直接返回
  printf("%s", ch);//打印\n
  fgets(ch, 11, pf1);//来到下一行,此时字符串有10个空间,第11的位置放\0,所要刚好
  printf("%s", ch);//打印hello bit\n
  fclose(pf1);
  pf1 = NULL;
  return 0;
}

image.png

4.1.3.fprintf、fscanf

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

fprintf和printf用法几乎一样只需在最前面加上所要输出的文件信息区的位置即可

返回值:成功的话是返回总字符个数、失败则返回一个负数并且报错

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

同样用法和scanf类似只是最前面加一个文件信息区的指针位置,

对于最后的.....是可变参数列表如:printf("%d %d %d",12,13,15); 此时参数可以同时多个输出

具体用法由下面代码展示:

struct S
{
  int a;
  char arr[20];
  float c;
};
int main()
{
  struct S s = { 100,"李四",120.00 };
  FILE* pf = fopen("test.txt","w");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  fprintf(pf,"%d %s %f",s.a,s.arr,s.c);//先输出到pf文件上
  fclose(pf);
  pf = NULL;
  FILE* pf1 = fopen("test.txt","r");
  if (pf1 == NULL)
  {
    perror("fopen");
    return 1;
  }
  fscanf(pf1,"%d %s %f",&(s.a),s.arr,&(s.c));//从文件中输入到内存中
  printf("%d %s %f\n", s.a, s.arr, s.c);//从内存中打印
  fclose(pf1);
  pf1 = NULL;
  return 0;
}

4.1.4.fread、fwrite

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

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

此时fread、fwrite是二进制的输入输出函数,所以输入和输出都是以二进制形式的

同样ptr表示写入 / 读取 的位置,

size 表示的是该类型的大小,

count该类型的个数,

stream文件信息区的地址。

具体使用:

//学生信息管理系统铺垫
struct S
{
  int a;
  char arr[20];
  float c;
};
int main()
{
  struct S s = { 123,"李四",321 };
  FILE* pf = fopen("test.txt", "wb");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  fwrite(&s, sizeof(struct S), 1, pf);
  fclose(pf);
  pf = NULL;
  struct S s1 = {0};
  FILE* pf1 = fopen("test.txt", "rb");
  if (pf1 == NULL)
  {
    perror("fopen");
    return 1;
  }
  fread(&s1, sizeof(struct S), 1, pf1);
  printf("%d %s %f", s1.a, s1.arr, s1.c);
  fclose(pf1);
  pf1 = NULL;
  return 0;
}

image.png

4.2sscanf、sprintf

知识点:

int sscanf ( const char * s, const char * format, ...);

sscanf从s处数据得到输入到指定内存,把字符串转化成一个格式化的数据

int sprintf ( char * str, const char * format, ... );

sprintf从指定内存中获得输出在str处,打一个格式化的数据转化成字符串

由此可以总结出:

scanf、printf,fscanf,fprintf,sscanf,sprintf

他们的不同类型的区别:

scanf类型:在最前面的参数是:所要获取数据的地方,如scanf的stdin(在此函数因为每次程序运行都会自动打开所以省略了),同样的fscanf的文件、stdin所有流、sscanf  的指定获得处 ;中间参数(const char * s)是指定的格式,最后是存放这些格式(...)的数据的地址,输入函数

printf类型:在最前面的参数(...)是:输出指定格式数据的位置,如prinf中的stdout;fprintf的所有流,sprintf的指定输出处; sprint中间参数(fchar * str)是指定的格式,最后的参数是从哪里获取的数据(...),输出函数

细节:

深入了解scanf、prinf后就能写出

  int main()
  {
    struct S s = { 123,"李四",321.0 };
    char tmp[100] = { 0 };
    sprintf(tmp , "%d %s %f",s.a,s.arr,s.c);//将结构体s的数据输出tmp内
    printf("%s\n", tmp);
    struct S s1 = { 0 };
    sscanf(tmp, "%d %s %f", &(s1.a), s1.arr, &(s1.c));//将tmp得到的数据输入到结构体s1内
    printf("%d %s %f", s1.a, s1.arr, s1.c);
    return 0;
  }

image.png

相关文章
|
3天前
|
存储 程序员 C语言
C语言:文件操作
C语言:文件操作
10 1
|
4天前
|
存储 C语言 C++
【C语言】文件与文件操作
前言:我们通过学习的技术可以完成计算与字符串处理,但程序结束之后就都消失了,这样岂不可惜。我们通过文件与数据持久化保存相关的基础知识。
8 0
|
6天前
|
存储 编译器 C语言
C语言中的文件操作指南
C语言中的文件操作指南
11 0
|
12天前
|
算法 C语言
【C 言专栏】C 语言文件操作的技巧与方法
【4月更文挑战第30天】本文介绍了C语言文件操作的关键技巧,包括文件的打开与关闭(使用`fopen`和`fclose`函数),读取(`fgetc`、`fgets`和`fread`)和写入(`fputc`、`fputs`和`fwrite`)操作。此外,还讨论了文件指针移动(`fseek`)、错误处理、文件权限和格式等问题。文中提供了一个简单的读写文件的示例,并提到了高级技巧如随机访问、文件缓冲和截断。掌握这些技能将有助于提升C语言编程中的文件处理能力。
|
18天前
|
C语言
C语言:内存函数(memcpy memmove memset memcmp使用)
C语言:内存函数(memcpy memmove memset memcmp使用)
|
3天前
|
存储 编译器 C语言
C语言:字符函数 & 字符串函数 & 内存函数
C语言:字符函数 & 字符串函数 & 内存函数
11 2
|
12天前
|
缓存 安全 编译器
【C 言专栏】C 语言函数的高效编程技巧
【5月更文挑战第1天】本文探讨了C语言中函数的高效编程技巧,包括函数的定义与作用(如代码复用和提高可读性)、设计原则(单一职责和接口简洁)、参数传递方式(值传递、指针传递和引用传递)、返回值管理、调用约定、嵌套与递归调用,以及函数优化技巧和常见错误避免。掌握这些技巧能提升C语言代码的质量和效率。
【C 言专栏】C 语言函数的高效编程技巧
|
14天前
|
C语言
pta浙大版《C语言程序设计(第3版)》 习题6-4 使用函数输出指定范围内的Fibonacci数 (20分)
pta浙大版《C语言程序设计(第3版)》 习题6-4 使用函数输出指定范围内的Fibonacci数 (20分)
|
14天前
|
C语言
pta 浙大版《C语言程序设计(第3版)》题目集 习题6-6 使用函数输出一个整数的逆序数 (20分)
pta 浙大版《C语言程序设计(第3版)》题目集 习题6-6 使用函数输出一个整数的逆序数 (20分)
|
14天前
|
C语言
(浙大版《C语言程序设计(第3版)》 习题6-5 使用函数验证哥德巴赫猜想 (20分)
(浙大版《C语言程序设计(第3版)》 习题6-5 使用函数验证哥德巴赫猜想 (20分)