Operator File(操作文件)

article/2025/9/19 17:46:06

Operator File - 操作文件

今天要讲的是 Operator File(操作文件),废话不多说。

在这里插入图片描述

本文看点

  • Operator File - 操作文件
    • 今天要讲的是 Operator File(操作文件),废话不多说。
  • 让我们开始吧!
    • 1.什么是文件?
    • 但是在我们程序设计中,我们一般谈的文件有两种:程序文件;二进制文件
      • 程序文件:
      • 数据文件:
    • 本章 讨论的是 数据文件。
      • 文件 其实是一种 存放数据 的 一种媒介 或者说 是一种 介质
    • 2.文件名
    • 3.文件类型
      • 一个数据 在内存中 是怎么存储的呢?
    • 接下来让我们通过实例来验证
    • 4.文件缓冲区
    • 5.文件指针
      • 缓冲文件系统 中,关键的概念是 “文件类型指针”,简称“文件指针”。
      • 在不同的 C 编译器 的 FILE 类型 包含的 内容 不完全 相同,但是大同小异。
    • 6.文件的打开和关闭
      • // FILE* fopen( const char* filename,const char* mode );
      • // int close( FILE* stream );
      • mode(打开方式):
      • 让我们开始实践吧!
    • 7.文件的顺序读写
      • 字符输出函数 fputc : int fputc( int c, FILE *stream );
      • 字符输入函数 fgetc
    • 那我们能不能让它像以前一样,键盘输入,屏幕显示?
    • 文本输入函数 fgets : char *fgets( char *string, int n, FILE *stream );
      • 文本输出函数 fputs :  fputs : int fputs( const char *string, FILE *stream );
      • 文本输出函数 fputs(标准输入输出形式)
      • 格式化输出函数 fprintf 所有输入流
      • 格式化输入函数 fscanf 适用所有输出流(标准 和 文件)
      • 让我们看看它们两个(fprintf 和 fscanf)的标准输出输入。
      • 对比一组函数(其实说白了就是相互转换,写进去,再拿出来):
        • fscanf / sscanf
        • fprintf / sprintf
        • scanf / printf 是针对 标准输入流 / 标准输出流 的 格式化输入 / 输出 语句
        • fscanf / fprintf 是针对 所有 输出/输入 流 的 格式化输入/输出 语句
        • sscanf / sprintf , 在比较这一对 之前,我先来了解一下,这两个函数
        • sscanf / sprintf
        • 二进制输出 fwrite :   size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
        • 二进制输入 fread: size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
    • 8.文件的随机读写
      • 现在就让我们来了解下 fseek 函数吧
      • origin 有下面几种写法:
      • ftell 函数: long ftell(FILE *stream);
      • rewind 函数:让文件指针 回到起始位置
    • 9.文件结束的判定
      • feof 函数 : int feof(FILE *stream);
      • 牢记:在文件读取过程中,不能使用 feof 函数 的 返回值 直接用来判断文件的 是否结束。 而是 应用于 当前文件 读取结束 的时候,判断是 读取失败 结束,还是 遇到文件尾 结束(就是说 我们已经知道文件读取已经结束了,但是 是 什么原因 导致 文件 结束的)
      • 1.文本文件 读取是否结束,判断返回子是否为 EOF( fgetc ), 或者 NULL (fgets)
        • 例如:
      • 2.二进制文件 的 读取结束判断,判断 返回值 是否小于 实际要读 的 个数
        • 例如: fread 判断返回值 是否小于 实际要读 的 个数
      • 二进制文件 与 文本文件差不多,就是读取的差别
        • while ((size_t c = fread(void *buffer, size_t size, size_t count, FILE *stream)) >=1)
        • fread返回实际读取的完整项的数量,如果发生错误或在达到count之前遇到文件结束,则可能小于count。使用feof或ferror函数来区分读错误和文件结束条件。如果size或count为0,fread返回0,并且缓冲区内容不变。
        • 也就是说 如果 count 为 0的话,肯定表示读取完成,如果读取异常结束,count 会大于0,说明还有数据没有读完。
    • 最后我们了解 一下 perror 函数
      • 由此可以看出 perror 其实可以看成, strerror 和 printf,还有 errno.h 的结合体(自动获取错误码,将其传化为错误信息的地址,并将其打印),唯一缺点就是 你用它,它就会打印错误信息,不可以不打印(很任性)。而 strerror 函数 可以控制不打印错误信息(只要不使用打印函数就行(如:printf,puts等)。


让我们开始吧!

在这里插入图片描述

1.什么是文件?

文件通俗来说,就是我们磁盘上的文件就是文件,看到下方附图,大家就说明都明白了文件的基本意思。(至于电脑有什么隐晦的文件,我什么都不知啊)
在这里插入图片描述

但是在我们程序设计中,我们一般谈的文件有两种:程序文件;二进制文件

程序文件:

包括源文件(后缀 ,c)、目标文件(后缀 .obj)、可执行文件(后缀 .exe)
在这里插入图片描述
如果没有显示文件的吼住的朋友,可以参考上图。



在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

扩展:
源文件,目标文件,可执行文件的联系:

源文件就是用汇编语言或高级语言写出来的代码保存为文件,目标文件是指源文件经过编译程序产生的能被cpu直接识别二进制文件。将目标文件链接起来就成了可执行文件。

源代码与源文件:

源代码(也称源程序)是指未编译的按照一定的程序设计语言规范书写的文本文件,是一系列人类可读的计算机语言指令。 在现代程序语言中,源代码可以是以书籍或者磁带的形式出现,但最为常用的格式是文本文件,这种典型格式的目的是为了编译出计算机程序。

计算机源代码的最终目的是将人类可读的文本翻译成为计算机可以执行的二进制指令,这种过程叫做编译,通过编译器完成。在大多数情况下,源代码等于源文件。

参考资料来源:百度百科-源文件




数据文件:

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

本章 讨论的是 数据文件。

在以前 所处理 数据的输入输出 都是以终端为对象的,即终端的键盘输入数据,运行结果 显示到 显示器上。
其实 有时候 我们会把 信息输出 到磁盘上,当需要的时候 再从磁盘上 把数据 读取到内存中 使用,这里 处理的就是 磁盘上 的 文件

文件 其实是一种 存放数据 的 一种媒介 或者说 是一种 介质








2.文件名

一个文件 要有 一个唯一的 文件标识,以便用户 识别引用, 文件名包含 3 部分: 文件路径 + 文件名主干 + 文件后缀
在这里插入图片描述
为了方便起见,文件标识 常被称为 文件名







3.文件类型

根据数据的组织形式,数据文件 被称为 文本文件 或者 二进制文件
数据 在内存中 以二进制的形式存储,如果 不加转换的 输出到  外存(硬盘),就是 二进制文件
如果要求在 外存(硬盘)上  以 ASCII码 的形式存储 ,则需要 在存储前 转换,以 ASCII 字符 的形式 存储的文件 是文本文件。


一个数据 在内存中 是怎么存储的呢?

 字符 一律 以 ASCII 形式存储,数值型数据 既可以用 ASCII 形式存储,也可以使用 二进制形式 存储。

如 有整数10000,如果以 ASCII 码 的形式输出到磁盘,则磁盘中占用 5 个字节(每个字符 一个字节,把 1 和 0 当做一个字符来处理)
在这里插入图片描述


接下来让我们通过实例来验证

 我们需要现在 该程序项目中创建一个 test.txt 文本文件,再来运行程序,没有这个文件程序都什么做不了
#include<stdio.h>
int main()
{int a = 10000;FILE* pf = fopen("test.txt", "wb"); // 打开 一个 test.txt 文件, "wb" == write binary(以二进制的形式 写到文件中)fwrite(&a/*数据来自于 a 地址处*/, 4/*写4byte*/, 1, pf);// fwrite 写文件,写 a的内容 进去,&a 表示数据来自于 a 的地址处,写 4 个byte//写 1个 这样的数据(写 1个 4 byte 的 数据),放到 pf 维护的文件里去fclose(pf);// 写完之后,就可以关闭这个文件了pf = NULL; // 需要置为 空指针,保护文件的安全。return 0;
}

写完之后,运行该程序,test.txt 文件内容已被改变,怎么观察呢?
解决方案资源管理器 -》 源文件 -》 反键 -》选择 添加 现有项 -》 选择 我们所创建的 test.txt 文件,点击添加
在这里插入图片描述
在这里插入图片描述



添加成功 ,选择 test.txt 文件 -》 反键 -》 选择 打开方式 -》 选择 二进制编译器(点击确定)
如果 不做这一步骤,直接点击查看,是没有效果的
在这里插入图片描述
在这里插入图片描述





此时 你点击 test.txt 文件 你就会发现 test.txt 文件显示的是 10000 以十六进制 形式 展示出的结果(内存上是二进制存储,现在只是以十六进制来展示): 10 27 00 00 (小端存储模式)
即 0x 00 00 27 10
在这里插入图片描述





4.文件缓冲区

ANSIC 标准 采用 "缓冲文件系统" 处理 数据文件的,所谓 缓冲文件系统 是指 系统 自动地 在内存中 为程序中 每一个正在使用的文件 开辟一块 "文件缓冲区"。
从 内存 向 磁盘 输出数据 会 先 送到 内存中的 缓冲区,装满 缓冲区 后 才  一起送到 磁盘 上。
如果 从 磁盘 向 计算机 读 入 数据,则 从磁盘文件中 读取数据 输入到 内存缓冲区(充满缓冲区),然后再从缓冲区 逐个地 将数据送到 程序数据区(程序变量等)。
缓冲区的大小 是根据 C 编译系统 决定的。

在这里插入图片描述


ensp;
让我们再通过 一道程序,来感受下 文件缓冲区

#include<stdio.h>
#include<Windows.h>
int mian()
{FILE* pf = fopen("test.txt", "w");fputs("abcdef", pf);Sleep(10000);printf("刷新缓冲区\n");fflush(pf);//刷新缓冲区时,才将缓冲区的数据 写到文件(磁盘)// fflush 在 高版本 的 vs 上 不能使用了。(这里使用的 vs2013)printf("在睡眠 10 s,此时,再次打开 test,txt 文件,文件有了内容");sleep(10000);fclose(pf);// fclose 在关闭文件的时候,也会刷新缓冲区// 使用 fflush 是是因为 为了大家更直接感受到 "文件缓冲区"pf = NULL;return 0;
}

未执行程序之前

在这里插入图片描述



记住执行程序之后,要快速打开文件,虽然给了20s时间(10s 时间没找到就尴尬了),此时文件中是没有数据的
在 10s 之内,打开文件,发现文件没有内容,说明 数据 此时 是在文件缓冲区中
在这里插入图片描述


我再来看看 10s 过后 ,程序调用fflush函数(刷新文件缓冲区),test.txt 文件 是否有 数据
在这里插入图片描述
效果证明,文件缓冲区 是存在的,在第一个10s里,要写入 文件中 的内容,存到了文件缓冲区中,随后 调用 fflush 刷新缓冲区,把文件缓冲区 里的 数据 写入 文件中。而后面的 10s,是因为 fclose 也可以 刷新缓冲区,这样写的目的,是为了让你觉得是 ffluse 把数据写到文件里,而不是 fclose,其实 就是为了让你清楚感受到 文件缓冲区 的存在。






5.文件指针

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

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

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

附图(vs2013):
在这里插入图片描述

在这里插入图片描述
每当打开一个文件的时候系统根据文件的情况 自动创建 一个 FILE 结构体并填充其中的信息,使用者不必关心细节。
一般都是 通过一个 FILE 的指针来维护 这个 FILE 结构体,这样使用起来更加方便。
 
** FILE* pf; 文件指针 pf.**

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

随着我们 通过 该文件指针(FILE) 访问或者修改文件指针 指向的 某个文件文件信息区该结构体也会跟着发生变化
也就是说 文件在 被 读取 写入 的时候,文件的大小,当前文件的指令,等等都会 发生变化





6.文件的打开和关闭

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

在编写程序的时候,在打开文件的同时,都会返回 FILE* 的指针 指向 该文件(文件的信息区),也相当于 建立了 指针 和 文件 的关系。
ANSIC 规定使用 fopen 函数 来 打开文件,fclose 来关闭文件。

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

// int close( FILE* stream );


mode(打开方式):

文件使用方式含义如果指定文件不存在
“r”(只读)为了输入数据,打开一个已经存在的文本文件出错
“w”(只写)为了输出数据,打开一个文本文件建立一个新的文件
“a”(追加)向 文本文件 尾 添加数据出错
“rb”(只读)为了输入数据,打开一个二进制文件出错
“wb”(只写)为了输出数据,打开一个二进制文件建立一个新的文件
“ab”(追加)向一个二进制文件尾添加数据出错
“r+”(读写)为了读和写,打开一个文本文件出错
“w+”(读写)为了读和写,建议一个新的文件建立一个新的文件
“a+”(读写)打开一个文件,在文件尾进行读写建立一个新的文件
“rb+”(读写)为了读和写,打开一个二进制文件出错
“wb+”(读写)为了读和写,新建一个新的二进制文件建立一个新的文件
“ab+”(读写)打开一个二进制文件,在文件尾进行读和写建立一个新的文件




让我们开始实践吧!

程序一(fopen函数):

#include<stdio.h>
int main()
{//打开文件(test.txt)// 相对路径 写法fopen("test.txt", "wb");  	//  . 表示当前路径fopen("../test,txt", "wb");//  .. 表示当前路径的上一级路径, 比如说  文件 1  包含该程序,文件2 包含 文件1 和 test.txtfopen("../../test.txt", "wb");// 当前路径的上上路径//绝对路径的写法fopen("G:\\程序\\operator file\\operator file\\test.txt", "wb");//  这里的双斜杠 \\  是为了 让 \ 单纯就是 斜杠。因为 \ 与其它字符相结合,会形成转义字符return 0;}



程序二(fclose函数):

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{//打开文件(test.txt)// 相对路径 写法FILE*pf = fopen("test.txt", "r"); // 在编写程序的时候,在打开文件的同时,都会返回 FILE* 的指针 指向 该文件(文件的信息区)// 也就是我们需要一个 FILE 类型的指针来接收//	但是fopen 有打开失败的可能性,打开失败 fopen 会返回一个 空指针if (!pf)// 如果 pf 为 NULL == 0,为假,取反 为真,执行 if 语句{printf("%s\n",strerror(errno));//输出错误信息return 0;// 程序结束}// 走这里说明打开成功// 读文件  "r"(只读)// 关闭文件fclose(pf);// 跟 free  函数 相似,free是释放动态空间(还给操作系统), fclose 的作用时 关闭 文件pf = NULL;// fclose 保护文件,free 保护 保护系统return 0;}



程序三(“w”打开方式):

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{//打开文件(test.txt)// 相对路径 写法FILE*pf = fopen("test.txt", "w"); // 在编写程序的时候,在打开文件的同时,都会返回 FILE* 的指针 指向 该文件(文件的信息区)// 也就是我们需要一个 FILE 类型的指针来接收//	fopen 有打开失败的可能性,打开失败 fopen 会返回一个 空指针// 打开方式 "w" 在指定文件不存在时,它创建一个文件,并返回它的地址,如果文件存在,且有内容的前提下,运行程序 它新建一个文件,而老文件的内容就销毁了说白了,就是如果你 当前文件中 不包含 test 文件时,且 打开方式 为 "w"(只写),它自动 生成 一个 test 的 文本文件// 所以并不会执行 if 语句 显示 报错if (!pf){printf("%s\n", strerror(errno));return 0;}// 走这里说明打开成功// 读文件  "r"// 关闭文件fclose(pf);pf = NULL;return 0;}






7.文件的顺序读写

功能函数名适用于
字符输入函数fgetc所有输入流
字符输出函数fputc所有输出流
文本输入函数gets所有输入流
文本输出函数fputs所有输出流
格式化输入函数fscanf所有输入流
格式化输出函数fprintf所有输出流
二进制输入fread文件
二进制输出fwrite文件




字符输出函数 fputc : int fputc( int c, FILE *stream );

在这里插入图片描述

在运行该程序之前,保证test。txt 文件 内容为空,这样方便我们观察现象
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{FILE* pf = fopen("test.txt", "w");if (!pf){printf("%s\n",strerror(errno));return 0;}// 写文件fputc('b', pf);// 输出一个 字符 到 文件 离去fputc('i', pf);fputc('t', pf);// 关闭文件fclose(pf);pf = NULL;return 0;
}

附图:
在这里插入图片描述





字符输入函数 fgetc

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (!pf){printf("%s\n", strerror(errno));return 0;}// 读文件printf("%c ", fgetc(pf));// bprintf("%c ", fgetc(pf));// iprintf("%c ", fgetc(pf));// t//关闭文件fclose(pf);pf = NULL;return 0;
}

附图:
在这里插入图片描述





那我们能不能让它像以前一样,键盘输入,屏幕显示?

答案是可以的。不过在实现之前,我们需要了解一下

从键盘输入 
输出到屏幕
键盘 & 屏幕 都是外部设备把 键盘 称为 标准输入设备 - stdin
把 屏幕 称为 标准输出设备 - stdout
是一个程序 默认打开 的 两个流设备除此之外,只要程序运行起来,它默认打开三个流
stdin
stdout
stderr:标准输出(设备)文件,对应终端的屏幕。进程将从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。在C中,程序执行时,一直处于开启状态。以上三个都默认打开的,这三个流的类型 都是 FILE* 的



让我们通过程序来了解下吧

#include<stdio.h>
int main()
{int ch = fgetc(stdin);// 从键盘输入,为什么要用 int ch 呢,MSDN 查看fputc(ch,stdout);// 在 屏幕上 输出return 0;}

在这里插入图片描述



文本输入函数 fgets : char *fgets( char *string, int n, FILE *stream );

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

我已经提前在 test.txt 写了bitHELLO#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{char buf[1024] = { 0 };// 创建一个数组,来存储 字符串FILE* pf = fopen("test.txt", "r");if (!pf){printf("%s\n", strerror(errno));return 0;}// 读文件fgets(buf,1024,pf);// 把 pf指向的 文件信息区 中 字符串,存储到 buf 数组 中//printf("%s\n",buf);// bit//// 请按任意键继续. . .//你会发现中间有个空格// 打印 一行数据 bit\nprintf("%s",buf);  // 把'\n'去掉 ==printf(buf);  //puts(buff)       // 则 // bit// 请按任意键继续. . .// 说明 buf 里面其实本来拥有一个 换行 (这点是需要注意的)// 打印第二行数据 HELLO ,HELLO  没有 \n, 因为\n 只拥有一个fgets(buf, 1024, pf);printf("%s", buf);// puts(buf)// 如果用 puts 你会发现每次打印都换行,因为 puts  天生就会在打印完之后,将其换行的 fclose(pf);pf = NULL;return 0;
}






文本输出函数 fputs :  fputs : int fputs( const char *string, FILE *stream );

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{char buf[1024] = { 0 };FILE* pf = fopen("test.txt", "w");if (!pf){printf("%s\n", strerror(errno));return 0;}// 写文件fputs("hello", pf);// 把 hello 写到 pf 里fputs("world", pf);// 自行点开 文件 看效果(helloword)// fputs 不会自动帮你换行,换行的话,需要我们在字符串后 加 \nfputs("\n",pf);fputs("hello\n", pf);// 把 hello 写到 pf 里fputs("world\n", pf);fclose(pf);pf = NULL;return 0;
}

在这里插入图片描述


文本输出函数 fputs(标准输入输出形式)

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{   // 从键盘读取一行文本char buf[1024] = { 0 };fgets(buf,1024,stdin);// 从标准输入读取fputs(buf,stdout);// 输出到 标准输出流(屏幕)// 此写法 等价于 gets(buf);//               puts(buf);return 0;
}

在这里插入图片描述



格式化输出函数 fprintf 所有输入流

                         int printf(const char *format[, argument]...);// 针对 标准输出流
int fprintf(FILE *stream, const char *format[, argument]...);// 所有输出流

你会发现 fprintf 和 printf 之间,就相差一个 流(FILE结构体的指针)。

#include<stdio.h>
#include<string.h>
#include<errno.h>struct s
{int n;float score;char arr[10];
};int main()
{                       // 不加 f ,默认为 double 类型struct s s = { 100, 3.14f, "bit" };FILE* pf = fopen("test.txt", "w");if (!pf){printf("%s\n", strerror(errno));return 0;}// 格式化的形式写文件fprintf(pf, "%d %f %s", s.n, s.score, s.arr);// fprintf 就是比 printf 多了个 流(FILE 结构 的 指针 pf )
把 结构成员的值 以 格式化数据 存入 pf 指向 文件信息区(文件)fclose(pf);pf = NULL;return 0;
}

在这里插入图片描述





格式化输入函数 fscanf 适用所有输出流(标准 和 文件)

                   int scanf(const char *format[, argument]...);int fscanf(FILE *stream, const char *format[, argument]...);

跟 fprintf 一样的,这里不多说 。直接看程序

#include<stdio.h>
#include<string.h>
#include<errno.h>struct s
{int n;float score;char arr[10];
};int main()
{                 struct s s = { 0 };FILE* pf = fopen("test.txt", "r");if (!pf){printf("%s\n", strerror(errno));return 0;}// 格式化的输入数据fscanf(pf, "%d %f %s", &(s.n), &(s.score), s.arr);// 从 pf 里 拿出 三个数据,分别以 %d %f %s 的格式,赋予 结构体成员变量printf("%d %f %s\n", s.n, s.score, s.arr);// 打印结构体成员变量fclose(pf);pf = NULL;return 0;}






让我们看看它们两个(fprintf 和 fscanf)的标准输出输入。

#include<stdio.h>
#include<string.h>
#include<errno.h>struct s
{int n;float score;char arr[10];
};int main()
{                       struct s s = { 0 };fscanf(stdin, "%d %f %s", &(s.n), &(s.score), s.arr);// 从 stdin(键盘) 输入 三个数据,分别以 %d %f %s 的格式,赋予 结构体成员变量fprintf(stdout, "%d %.2f %s", s.n, s.score, s.arr);// 打印结构体成员变量return 0;}

在这里插入图片描述





对比一组函数(其实说白了就是相互转换,写进去,再拿出来):

fscanf / sscanf

fprintf / sprintf

scanf / printf 是针对 标准输入流 / 标准输出流 的 格式化输入 / 输出 语句

fscanf / fprintf 是针对 所有 输出/输入 流 的 格式化输入/输出 语句


sscanf / sprintf , 在比较这一对 之前,我先来了解一下,这两个函数

sscanf 函数:   Read formatted data from a string. 从一个字符串里,把 格式化数据 拿出来
int sscanf(const char *buffer, const char format[, argument] …);
比 scanf 多了 一个 const char
buffer

sprintf 函数:  Write formatted data to a string. 写 格式化数据 给 一个字符串
int sprintf(char *buffer, const char format[, argument] …);
比 printf 多了 一个 const char
buffer

#include<stdio.h>struct s
{int n;float score;char arr[10];};int main()
{struct s s = { 100, 3.14f, "abcdef" };struct s tmp = { 0 };// 创建一个结构体变量,用来存储 sscanf 函数 将字符串 转化 成格式化 的数据char buf[1024] = { 0 };// 见一个字符数组,用来 存储 sprintf 函数 把 格式化数据  写成 成字符串 类型的 数据// 先写进去,再读,没东西怎么读// 格式化 的 数据 转换 字符串 存储到 bufsprintf(buf, "%d %f %s", s.n, s.score, s.arr);// sprintf 将这里的数据转化为成字符串类型//printf("%s\n", buf);// 100  3.1400 abedef//这里的 100  3.14 abcdef 都是转化成了字符串的//从 buf 中 读取 格式化 的 数据 到tmpsscanf(buf, "%d %f %s", &(tmp.n), &(tmp.score), tmp.arr);//将 buf 中的 数据,再重新转换为 它们 原来的类型printf("%d %f %s", tmp.n, tmp.score, tmp.arr);return 0;
}

在这里插入图片描述
经过上面讲解的,相信大家已经理解差不多到位了,让我们分析分析 这两个函数的用途。

sscanf / sprintf

// sscanf 是 从 字符串 中读取 格式化 的数据(把字符串中数据,转化成格式化数据,赋给其它变量)
// sprintf 是把 格式化数据 输出成(存储到)字符串(把 格式化的数据,转化成(或者说 写成)字符串形式 存入某块空间(文件)里,有或者输出到(打印)外端(屏幕))。






二进制输出 fwrite :   size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );

buffer
Pointer to data to be written 指向要写入数据的指针size
Item size in bytes  元素 的 大小单位  bytecount
Maximum number of items to be written  最多要被写 的 元素个数stream
Pointer to FILE structure 指向 FILE 结构体的指针 


程序如下:

#include<stdio.h>struct s
{char name[20];int age;double score;// score  分数/成绩
};int main()
{struct s s = { "张三", 20, 55.6 }; FILE* pf = fopen("test.txt", "wb");if (!pf){return 0;}//  "wb" 二进制形式写文件fwrite(&s, sizeof(struct s), 1, pf);// test,txt 里面的内容为: 张三                   吞烫烫K@//张三的 二进制,ASCII 形式 存储都一样的,其他就不是了,所以 后面的内容看不懂,是因为该数据 是以二进制写进的// 关闭文件fclose(pf);pf = NULL;return 0;
}



二进制输入 fread: size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

buffer
Storage location for data   存储数据的位置size
Item size in bytes  元素大小,单位字节count
Maximum number of items to be read 最多 读取多少 个 元素stream
Pointer to FILE structure 指向 FILE 结构体 的 指针


程序如下:

#include<stdio.h>struct s
{char name[20];int age;double score;// score  分数/成绩
};int main()
{struct s tmp = { 0 };FILE* pf = fopen("test.txt", "rb");if (!pf){return 0;}//  二进制形式读文件fread(&tmp, sizeof(struct s), 1, pf);// 从 pf 里拿出 一个 大小为 sizeof(struct s) 的结构体,将其值赋给 结构体变量 tmpprintf("%s %d %lf\n", tmp.name,tmp.age, tmp.score);// 关闭文件fclose(pf);pf = NULL;return 0;
}







8.文件的随机读写

说到随机读写就要涉及到一个函数  fseek

现在就让我们来了解下 fseek 函数吧

fseek 函数 :
Moves the file pointer to a specified location.  将文件指针移动指定位置int fseek(FILE *stream, long offset, int origin);stream
Pointer to FILE structure    FILE 结构体 的 指针offset
Number of bytes from origin  从原点开始的字节数(偏移量)origin
Initial position     起始位置  (文件指针的当前位置)   

origin 有下面几种写法:

SEEK_CUR
Current position of file pointer  文件指针的当前的位置SEEK_END
End of file  文件的末尾SEEK_SET
Beginning of file 文件起始位置


程序实践:

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{FILE* pf = fopen("test.txt", "r");// test.txt 的内容为 abcdefif (!pf){printf("%s\n", strerror(errno));return 0;}//  1.定位文件指针:根据 文件指针的位置 和 偏移量 来定位文件指针fseek(pf, 4, SEEK_CUR);// 从文件当前的位置,偏移量为 4, 指向 e//fseek(pf, -2, SEEK_END);// 从文件的末尾位置,想要得到 e ,偏移量应该 为 -2(文件指针指向 f 的后面,也就是偏移量为 0 的位置)//  2.读取文件int ch = fgetc(pf);printf("%c\n", ch);// e//  3.关闭文件fclose(pf);pf = NULL;return 0;
}






ftell 函数: long ftell(FILE *stream);

Gets the current position of a file pointer. 得到文件指针 目前的位置
( 返回 文件指针 相对于 起始位置 的 偏移量 )

程序一:

#include<stdio.h>
#include<errno.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (!pf){printf("%s\n", strerror(errno));return 0;}// 返回 文件指针 当前的位置int pos = ftell(pf);//文件指针 没有 fseek 处理,所以 文件指着 位置 指向 起始位置(偏移量为 0 的位置)printf("%d\n", pos);//    0fclose(pf);pf = NULL;return 0;
}


程序二:

#include<stdio.h>
#include<errno.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (!pf){printf("%s\n", strerror(errno));return 0;}// 1.定位文件指针fseek(pf, 4, SEEK_CUR);// 返回 文件指针 当前的位置int pos = ftell(pf);// 因为前已经 fsek ,文件指针 指向 偏移量为 4 的位置printf("%d\n", pos);//    4fclose(pf);pf = NULL;return 0;
}


程序三:

#include<stdio.h>
#include<errno.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (!pf){printf("%s\n", strerror(errno));return 0;}// 1.定位文件指针fseek(pf, 4, SEEK_CUR);// 此时文件位置指向 偏移量为 4 的位置,指向 eint ch  = fgetc(pf);// fgetc 读取到了 e, 文件指针pf指向下一个位置,偏移量为 5 的位置// 返回 文件指针 当前的位置int pos = ftell(pf);// 因为前已经 fgets 一次,文件指针 不再指向 偏移量为 4 的位置,而是偏移量为 5 的位置// pos == 5printf("%c\n", ch); //    eprintf("%d\n", pos);//    5fclose(pf);pf = NULL;return 0;
}






rewind 函数:让文件指针 回到起始位置


程序实践:

test.txt 内容 abcdef
#include<stdio.h>
#include<errno.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (!pf){printf("%s\n", strerror(errno));return 0;}// 1.定位文件指针fseek(pf, 4, SEEK_CUR);// 此时文件指针指向 偏移量为 4 的位置,即指向 e//这时 让文件指针回到起始位置rewind(pf);// 此时再 fgetc ,读取的应该是 aint ch = fgetc(pf);printf("%c\n", ch); //    afclose(pf);pf = NULL;return 0;
}







9.文件结束的判定

feof 函数 : int feof(FILE *stream);


被错误使用的 feof 函数 :

#include<stdio.h>
int main()
{//EOF(-1) - end of file 文件结束标志// 那么 feof  是用来判断 文件的结束,其实不是FILE* pf = fopen("test.txt","r"); //  在执行该程序之前,把 test.txt  文件里面的内容先清空// 因为如果文件里什么都没有,那么我们第一次 fgetc 读到就是 EOFif (!pf){return 0;}int ch = fgetc(pf);printf("%d\n", ch);// -1 == EOF(文件结束标志),说明文件结束的位置 放了一个 EOFfclose(pf);pf = NULL;return 0;
}


牢记:在文件读取过程中,不能使用 feof 函数 的 返回值 直接用来判断文件的 是否结束。 而是 应用于 当前文件 读取结束 的时候,判断是 读取失败 结束,还是 遇到文件尾 结束(就是说 我们已经知道文件读取已经结束了,但是 是 什么原因 导致 文件 结束的)

1.文本文件 读取是否结束,判断返回子是否为 EOF( fgetc ), 或者 NULL (fgets)

例如:

  1. fgetc 判断是否为 EOF
  2. fgets 判断返回值是否为 NULL

2.二进制文件 的 读取结束判断,判断 返回值 是否小于 实际要读 的 个数

例如: fread 判断返回值 是否小于 实际要读 的 个数


程序实践:

#include<stdio.h>
#include<stdlib.h>
int main()
{int c;// 用来接收 fgetc 的返回值FILE* pf = fopen("test.txt", "r");if (!pf)// 所以必定 运行 if 语句{perror("File opening failed");// 打印错误信息,最后我为其讲解一下return EXIT_FAILURE/*表示 -1 ,表示文件打开失败的状态值*/;}// 如果 要打开的文件 不存在,程序到这里 打印错误信息就结束了// 打开成功while ((c = fgetc(pf)) != EOF) // 读一个,打印一个,如果 读到 'EOF == -1 ',跳出 while 循环语句{ // 标准 I/O 读取文件循环 putchar(c);}//判断什么时候结束的if (ferror(pf))// 如果 流(pf),没有出错,ferror 返回 0(读取成功),除此之外 返回 一个 非0 的数 (读取失败){ puts("I/O error when reading");// test.txt 文件在读写时, 非正常结束读取// 这里是读取成功,所以不执行 if 语句}else if (feof(pf))// feof 判断  pf  是不是  因为遇到(读取到) EOF 而结束的// feof 返回的值 为 非零,说明是因为遇到 EOF 而结束的// 如果当前位置不是文件结束,则返回0。没有返回信息{puts("End of file reached successfully");// 因为该文件是因为 读到 EOF 结束的,所以,返回一个 非零的值// 执行该语句,打印语句内容,表示  文件是读取遇到了 EOF(文件的结束标志),正常结束的,}fclose(pf);pf = NULL; return 0;
}







二进制文件 与 文本文件差不多,就是读取的差别

while ((size_t c = fread(void *buffer, size_t size, size_t count, FILE *stream)) >=1)

fread返回实际读取的完整项的数量,如果发生错误或在达到count之前遇到文件结束,则可能小于count。使用feof或ferror函数来区分读错误和文件结束条件。如果size或count为0,fread返回0,并且缓冲区内容不变。

也就是说 如果 count 为 0的话,肯定表示读取完成,如果读取异常结束,count 会大于0,说明还有数据没有读完。







最后我们了解 一下 perror 函数

先举个例子:

#include<stdio.h>
#include<errno.h>// 错误码 库
int main()
{FILE* pf = fopen("test.txt", "r");if (!pf){//printf("%s\n", strerror(errno));// strerror - 把 错误码 对应的错误信息 的 字符串 得治 返回return 0;    // strerror 函数 需要配合 errno.h 头文件,才能打印错误信息}return 0;
}





再来看看 perror 函数

#include<stdio.h>
int main()
{FILE* pf = fopen("test2.txt", "r");// test2.txt  文件是不存在的if (!pf)// 所以肯定是打开失败的,执行 if 语句{perror("hehe");// 屏幕 上 打印 hehe: No such file or directory// 由此 不难看出:这里的 hehe  就是 问题的名字// 而且 perror 该函数不需借助 strerror 函数(转换错误码信息)和 errno.h(提供错误码) 头文件,还有 printf 打印函数(打印错误信息)// 直接就能直接打印出 错误信息return 0;}// 读文件// 关闭文件fclose(pf);pf = NULL;return 0;
}

由此可以看出 perror 其实可以看成, strerror 和 printf,还有 errno.h 的结合体(自动获取错误码,将其传化为错误信息的地址,并将其打印),唯一缺点就是 你用它,它就会打印错误信息,不可以不打印(很任性)。而 strerror 函数 可以控制不打印错误信息(只要不使用打印函数就行(如:printf,puts等)。


本文就此结束。

在这里插入图片描述


http://chatgpt.dhexx.cn/article/mnXIOL60.shtml

相关文章

Hadoop_Filesystem

直接使用FileSystem 创建一个路径 import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IOUtils; import org.junit.Test; import java.io.IOException; import java.net.…

MFC Shell文件操作SHFileOperation

外壳函数&#xff08;Shell&#xff09;--------SHFileOperation Copies, moves, renames, or deletes a file system object.文件复制、移动、重命名或者删除 int SHFileOperation( __in LPSHFILEOPSTRUCT lpFileOp ); 其参数lpFileOp是一个指向SHFILEOPSTRUCT结构的…

hdfs Java API 删除文件

文章目录 hdfs Java API 删除文件一、创建目录二、判断文件是否存在三、判断path指向的是目录还是文件四、删除文件 hdfs Java API 删除文件 要删除目录之前&#xff0c;首先创建一个目录给我们删&#xff0c;在hdfs上创建一个/ied011目录 一、创建目录 下面是代码具体的步骤…

python 删除文件到回收站 SHFileOperation

python如果要删除一个文件&#xff0c;通常使用 os.remove(filename) 但是这样就直接从磁盘删除了。 有些文件需要删除到回收站 方法如下 &#xff1a; def del_file(filename):print(delete file, filename)# os.remove(filename) #直接删除文件&#xff0c;不经过回收站…

VB利用SHFileOperation实现拷贝、删除、重命名文件

Private Declare Function SHFileOperation Lib “shell32.dll” Alias “SHFileOperationA” (lpFileOp As SHFILEOPSTRUCT) As Long Private Type SHFILEOPSTRUCT hwnd As Long ’ wFunc As Long pFrom As String pTo As String fFlags As Integer fAnyOperationsAborted As …

Linux下rar文件的压缩与解压

Linux下rar文件的压缩与解压 工具&#xff1a;rar、unrar 链接:https://pan.baidu.com/s/1MP7XupLUtkf6JxLkRUH78g 密码:k431 一、上传到任意目录 二、解压 三、查看软件信息 四、创建软件系统路径 本次主要的是rar、unrar两个软件服务 五、服务搭建完成 此时&#xff0c;…

linux下解压rar和7z压缩文件

在windows下我们压缩解压文件通常后缀为rar&#xff0c;在linux下我们压缩解压文件通常后缀为tar 默认在linux下我们不能解压压缩rar文件 我们可以下载rarlinux安装包实现解压压缩后缀为rar的包 下载地址&#xff1a;WinRAR archiver, a powerful tool to process RAR and ZIP …

Linux【工具 01】rarlinux工具下载安装处理.rar格式文件实例

1.说明 要安装一个.rar格式的应用&#xff0c;上传 Linux 系统后发现没有解压工具&#xff0c;上网搜索后开始一波三折的旅程。 2.安装 2.1 跳坑 # 有小伙伴分享安装方法 yum install rar # 安装后根本无法使用 unrar 命令2.2 一波三折 WinRAR 官网下载 这里有各种操作系统…

linux系统下解压rar文件

1、下载linux版本的rar软件 访问官网 下载最新的、适用于自己的linux版本的rar软件。 可以在服务器终端通过命令getconf LONG_BIT查看自己的linux服务器的字长。我的是64位的&#xff0c;就下载图示箭头所指的版本 下载之后&#xff0c;传到服务器上&#xff0c;最好单独放在一…

Linux安装Rar软件与压缩、解压方法

在Win10上压缩的文件&#xff0c;一般以.rar结尾&#xff0c;这个压缩包如果要在Linux上解压&#xff0c;就需要用到Rar软件&#xff0c;下面介绍在Ubuntu v16.04 上安装Rar软件。 1 设置apt镜像源 设置apt镜像源&#xff0c;请参考这篇文章: https://blog.csdn.net/sanqima/…

Linux安装rar

安装rar 1、直接使用yum安装输入命令 wget --no-check-certificate http://www.rarsoft.com/rar/rarlinux-4.0.1.tar.gz 如果没有wget命令&#xff0c;需要先装一下 Yum -y install wget –no-check-certificate 这个是无视风险&#xff0c;这个网站好像出了点问题&#xff0c;…

html网页字体出现模糊,浏览器打开网页字体模糊问题的解决方法

前面脚本之家小编介绍了打开网页字体变大了怎么办的相关内容&#xff0c;如果你也遇到这种故障可以去前面找找脚本之家小编写的这篇教程。那么如果不是出现打开网页字体变大而是打开网页字体模糊怎么办&#xff1f;其实造成这种网页字体的故障首先是考虑到用户对浏览器设置错误…

html字体字号颜色怎么设置,HTML 字体颜色怎么设置?

HTML 字体颜色怎么设置? 在网页开发的过程中, 有时为了网页的美观, 需要给网页中的字体设置不同的颜色. 那么怎么设置字体颜色呢? 下面本篇文章就来给大家来介绍设置字体颜色的几种方法, 希望对大家有所帮助. 方法 1: 使用 < font > 标签的 color 属性设置字体颜色 col…

php怎么显示好看的字体颜色,网页中字体颜色设置方法的总结

那么我都知道网页中颜色的运用是网页必不可少的一个元素。使用颜色目的在于有区别、有动感、美观之用&#xff0c;同时颜色也是各种各样网页的样式表现元素之一,别急&#xff01;接下来详细为大家分别介绍通过html、CSS、JS/JQ进行字体颜色设置的方法。 字体颜色设置的相关总结…

css字体设置为白色,css怎么将字体设置成白色

css怎么将字体设置成白色 css将字体设置成白色的方法:可以通过使用color属性来指定字体的颜色,如【color: white】或【color: #fff】。color属性用于指定文本的颜色,颜色值可以是颜色名称或十六进制值。 环境: 本文适用于所有品牌的电脑。 (学习视频分享:css视频教程) 相关…

worder字体网页字体对照表

运营同学一直说设置的字体不对&#xff0c;在word上设置好的格式&#xff0c;复制到网站上之后&#xff0c;字体就变小了。 说这是个程序bug&#xff0c;发现怎么解释都解释不了了。 然后心理就有点不平衡&#xff0c;直接找到了字体对照表 字体对照表&#xff1a;大特号&…

html设置幼圆字体,CSS font-family中文字体设置方法

网站上的字体样式都是通过CSS来控制的&#xff0c;CSS font-family属性可以设置文字字体样式。 常用的网站字体设置代码如下&#xff1a; body{font-family:"Microsoft Yahei","Hiragino Sans GB","Helvetica Neue",Helvetica,tahoma,arial,Verd…

html5怎么设置字体位置,css如何设置字体位置

css设置字体位置的方法&#xff1a;1、使用【text-align】属性设置字体的位置&#xff1b;2、使用position属性设置字体位置&#xff1b;3、使用padding、margin属性设置字体位置。 本教程操作环境&#xff1a;windows10系统、css3版&#xff0c;DELL G3电脑&#xff0c;该方法…

php网页代码字体大小,html字体大小怎么设置

设置html字体大小的方法&#xff1a;1、【font-size】后面加px值的方式&#xff1b;2、使用inherit继承父元素的字体大小&#xff1b;3、设置固定的几个值&#xff1b;4、设置smaller和larger&#xff1b;5、设置百分比的形式。 本教程操作环境&#xff1a;windows10系统、html…

怎么调整网页页面大小在HTML中,网页字体大小设置方法 怎么改网页字体大小

经常有电脑爱好者朋友由于不小心误操作导致电脑浏览网页时出现了字体变大或变小等&#xff0c;导致使用不习惯。昨天刚好有电脑百事网网友又问到的网页字体大小设置的问题&#xff0c;所以今天编辑与大家简单介绍下网页字体大小怎么设置。 其实很多朋友出现网页字体变大或变小都…