C语言文件读写函数介绍【滴水逆向三期(39)笔记】

简介: C语言文件读写函数介绍【滴水逆向三期(39)笔记】

引言

在之前的学习中,我们了解了C语言指针和多级指针“骚操作”:隐藏代码到数据区(函数指针)函数指针,在学习到后面需要提取程序的PE文件结构时,我发现必须要用到C语言的文件读写函数,在这里我们来介绍一下C语言的文件读写函数。

文件分类

在学习文件读写函数之前,我们先来了解一下文件类型:在C语言中,按照数据存储的编码形式,数据文件可以分为文本文件和二进制文件两种。

文本文件

文本文件是以ASCII码值进行存储与编码的文件,其文件的内容就是字符,存储的是ASCII码的二进制,也就是我们能够直观的看得懂的,比如:‘2’,‘34’,‘5’这样,文件的数据流为字符流。

二进制文件

二进制文件是存储二进制数据的文件,存储的是数据的补码,文件的数据流为二进制流。

文件读写函数

一.关于FILE

在学习文件读写函数之前,我们先来了解一下在我们使用所有文件读写函数时,定义的结构指针FILE:

FILE是C语言为了具体实现对文件的操作而定义的一个包含文件操作相关信息的结构类型,FILE *fp定义了一个结构指针,FILE类型是用typedef重命名的,在头文件stdio.h中定义,因此,使用文件读写函数时都需要#include<stdio.h>。

下面是FILE文件类型的说明:

typedef struct{
short level;//缓冲区使用量
unsigned flags;//文件状态描述
char fd;//文件描述符
shotr bsize;//缓冲区大小
unsigned char *buffer;//文件缓冲区的首地址
unsigned char *curp;//指向文件缓冲区的首地址
unsigned char hold;//其他信息
unsigned istemp;
short token;
}FILE;

1.打开文件和关闭文件

1.打开文件

打开文件功能用于建立系统与要操作的某个文件之间的关联,指定这个文件名并请求系统分配相应的文件缓冲区内存单元。打开文件由标准函数fopen()实现,其调用方式一般为:

fopen("文件名","打开方式");

这里我们给出函数原型:

FILE *open(char *name,char *mode);

函数原型中的name即文件名,mode为打开方式。在这里我们给出C语言所有的文件打开方式:

文件打开方式
使用方式 含义 使用方式 含义
“r" 打开文本文件进行只读 ”rb" 打开二进制文件只读
“w” 新建新文本文件进行只写 “wb” 建立二进制文件进行只写
“a" 打开文本文件进行追加 “ab" 建立二进制文件进行写/追加
”r+" 打开文本文件星星读/写 “rb+” 打开二进制文件进行读/写
“w+” 建立新文本文件进行读/写 “wb+” 建立二进制文件进行读/写
“a+" 打开文本文件进行读/写/追加 ”ab+“ 打开二进制文件进行读/写/追加

值得注意的是:fopen( )函数有返回值,如果文件成功打开或建立,则返回包含文件缓冲区等信息的FILE结构指针,如果未能成功打开或建立,则返回NULL(空值)的FILE指针。

为保证文件操作的可靠性,调用fopen( )函数时最好做一个判断,以确保正常打开后再进行读写。其形式为:

if((fp=fopen("abc.txt","r"))==NULL){
  printf("File open error!\n");
  exit(0);
}

这里的exit(0)是系统标准函数,作用是关闭所有文件,并且终止程序的执行。参数0表示程序正常结束,非0参数通常表示不正常的程序结束。

这里还需要注意:文件一旦经fopen()正常打开,则对该文件的操作方式就被确定,并且直至文件关闭都不变,即若文件以r方式打开,则只能对该文件进行读操作,而不能进行写入数据操作。

一般进行文件读写操作时,常用到一下规则:

if 读文件
    指定的文件必须存在,否则出错;
if 写文件(指定的文件可以存在也可以不存在)
  if 以“w”方式写
    if 文件已存在
      源文件将被删去后重新建立;
    else
      按指定的名字创建一个新文件;
  if 以“a”方式写
    if 文件已存在
      写入的数据将被添加到指定文件原有的数据后面,不会删去原有的内容;
    else 
    按指定的名字新建一个文件(与“w”相同);
  if 文件同时读和写
    使用“r+”“w+”或“a+”打开文件;

2.关闭文件

当文件操作完成后,应及时关闭它以防止不正常的操作。

关闭文件通过调用标准函数fclose()实现,其一般格式为:

fclose(文件指针);

该函数将返回一个整数,若该数为0表示正常关闭文件,否则标志无法正常关闭文件,所以关闭文件时也应该使用条件判断:

if(fclose(fp){
  printf("Can not close the file!\n");
  exit(0);
}

关闭文件操作除了强制把缓冲区的数据写入磁盘外,还将释放文件缓冲区单元和FILE结构指针,使文件指针与具体文件脱钩。

二.文件读写

1.字符方式读写函数fgetc()和fputc()

对于文本文件,存取的数据都是ASCII码字符文本,使用这两个函数读写文件时,逐个字符地进行文件读写。

(1).fgetc()

功能:实现从fp所指示的磁盘文件读入一个字符到ch。

函数调用格式:

ch=fgetc();
(2).fputc()

功能:把一个字符ch写到fp所指示的磁盘文件上。

函数调用格式:

futc(ch,fp);

返回值:若写文件成功,则返回ch,若写文件失败,则返回EOF。

2.字符串方式文件读写函数fputs( )和pgets( )

(1).fgets( )

功能:从文本文件中读取字符串。

函数调用格式:

fgets(s,n,fp);

其中s可以是字符数组名或者字符指针,n是指定读入的字符个数,fp时文件指针。

值得注意的是:函数被调用时,最多读取n-1个字符,当函数读取的字符达到指定个数,或接收到换行符,或接收到文件结束标志EOF时,将在读取的字符后面自动添加一个‘\0’字符。若有换行符,则将换行符保留(换行符在’\0’字符之前),若有EOF,则不保留EOF。

返回值:若成功读取,则返回读取的字符串,若读取失败,则返回空指针。

(2).fputs( )

功能:向指定的文本写入一个字符串。

函数调用格式:

fputs(s,fp);

其中s为要写入的字符串,可以是字符数组名,字符型指针变量或者是字符串常量,fp是文件指针。该函数把s写入文件时,字符串结束符’\0’不会被写入文件。

返回值:若成功写入,则返回所写的最后一个字符,若写入失败,则返回EOF。

3.格式化方式文件读写函数fscanf( )和fprintf( )

(1).fscanf( )

功能:从文件中按照给定的控制格式读取数据

函数调用格式:

fscanf(fp,格式字符串,输入表);
(2).fprintf( )

功能:按照给定的控制格式向文件中写入数据

函数调用格式:

fscanf(fp,格式字符串,输出表);

4.数据块方式文件读写函数fread( )和fwrite( )

这两个函数多用于读写二进制文件。

(1).fread( )

功能:可以用来读一组数据,如一个数组元素,一个结构变量的值等。二进制文件中的数据流是非字符的,它包含的是数据在计算机内部的二进制形式。

函数调用格式:

fread(buffer,size,count,fp);

其中buffer是一个指针,在函数fread( )中,他表示存放输入数据的首地址,size表示数据块的字节数,count表示要读写的数据块数。

如:fread(fa,4,5,fp);表示从fp所指的文件中,每次读4个字节送入实数组fa中,连续读5次,即读5个实数到fa中。

返回值:成功读取到的次数

注意:size未读满时,算作读取失败

(2).fwrite( )

功能:可以用来写入一组数据,如一个数组元素,一个结构变量的值等。

函数调用格式:

fwrite(buffer,size,count,fp);

其中buffer表示存放输出数据的首地址,size表示数据块的字节数,count表示要读写的数据块数。

返回值:成功写入的次数

三.其他相关函数

1.文件定位函数

在文件读写的整个过程中,每一次成功的操作都将改变文件指针的位置,依次完成文件数据的访问与处理。

(1).重定位文件首函数rewind( )

功能:定位文件读写位置指针,使其指向读写文件的首地址,即打开文件时文件读写位置指针所指向的位置。

当访问某个文件,进行了文件读写,使指针指向了文件中间或末尾,又想回到文件的首地址重新进行读写时,可使用该函数,其调用格式为:

rewind(FILE *fp);
(2).指针移动控制函数fseek( )

功能:控制指针移动

函数调用格式:

fseek(fp,offset,form);

其中fp为文件指针,offset表示移动偏移量,它应该是long型数据,使用常量时,应加上后缀“L”,offset可为负值,form表示从哪个位置开始计算偏移量,位置可取三种:文件首部,当前位置和文件尾部,实际表示时分别对应值0、1、2,或常量SEEK_set,SEEK_CUR,SEEK_END。

(3).获取指针当前位置函数ftell( )

功能:获取当前文件读写位置,即相对于文件开头的偏移量(字节数)。

函数调用格式:

ftell(文件指针);

函数出错时返回-1L。

2.检测文件指针状态函数

(1).文件末尾检测函数feof( )

功能:判断fp指针是否已经到文件末尾,即读文件是否读到了文件结束的位置。

函数调用格式:

feof(fp);

返回值:成功返回1表示已经读到了文件末尾的位置,0表示文件未结束。

(2).读写错误检查函数ferror( )

功能:检查文件在用各种输入输出函数进行读写时是否出错。

函数调用格式:

ferror(fp);

返回值:若为出错,返回0,否则表示出错。

(3).出错标记清除函数clearerr( )

功能:清楚出错标志和文件结束标志,使他们为0值。

函数调用格式:

clearerr(fp);

文件指针必须是已经定义过的。

好了,有了这些知识,我们再加以练习,课程中的问题也就迎刃而解啦,相信大家学完后可以独立写出PE头部字段分析的程序啦,作业我会在之后上传到博客,期待大家的阅读。

关于C语言文件读写函数的介绍就到此为止,非常希望大家能够找出错误之处并提出宝贵意见,我将虚心接受!!!望我们共同进步!!!

相关文章
|
3月前
|
存储 C语言
`scanf`是C语言中用于按格式读取标准输入的函数
`scanf`是C语言中用于按格式读取标准输入的函数,通过格式字符串解析输入并存入指定变量。需注意输入格式严格匹配,并建议检查返回值以确保读取成功,提升程序健壮性。
990 0
|
5月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
321 15
|
11月前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
611 23
|
6月前
|
存储 编译器 程序员
c语言的文件操作与文件缓冲区
如果没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运行程序,是看不到上次程序的数据的,如果要将数据进行持久化的保存,我们可以使用文件。磁盘(硬盘)上的文件是文件。但是在程序设计中,我们⼀般谈的⽂件有两种:程序文件、数据文件(从文件功能的角度来分类 的)。就比如说我们电脑中以.txt为后缀的就是文件的一种,他就是数据文件。.exe为后缀的就为程序文件。函数名功能适用范围fgetc字符输入函数所有输入流fputc字符输出函数所有输出流fgets。
153 0
|
10月前
|
人工智能 Java 程序员
一文彻底搞清楚C语言的函数
本文介绍C语言函数:函数是程序模块化的工具,由函数头和函数体组成,涵盖定义、调用、参数传递及声明等内容。值传递确保实参不受影响,函数声明增强代码可读性。君志所向,一往无前!
393 1
一文彻底搞清楚C语言的函数
|
10月前
|
人工智能 C语言
|
11月前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
246 24
|
11月前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
581 16
|
11月前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
472 3
|
11月前
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
369 2