前言:在上一篇博客关于文件的基础知识中我们对文件有了一定的了解,本篇博客将会详细讲解操作文件的函数。

文章目录

  • 文件的顺序读写
    • 字符输入输出函数 —— fgetc 与 fputc
      • fputc函数
      • fgetc函数
    • 文本行输入输出函数 —— fgets 与 fputs
      • fputs函数
      • fgets函数
    • 格式化输入输出函数 —— fscanf 与 fprintf
      • fprintf函数
      • fscanf函数
      • 扩展(函数对比)
    • 二进制输入输出函数 —— fread与 fwrite
      • fwrite函数
      • fread函数
  • 文件的随机读写
    • fseek函数
    • ftell函数
    • rewind函数
  • 文件读取结束的判定

文件的顺序读写

文件顺序读写的函数如下,接下来我们将一一介绍这些函数。

注:在使用这些函数之前要引用头文件 <stdio.h>

在此之前,我们需要知道关于 (stream) 的一些概念:
流是一个高度抽象的概念,如图:

即程序向流这个层次中输入数据,流再把相应的数据写到不同的设备上(至于如何写的,目前不用我们关心这些细节);例如:当我们打开文件,在写文件时,就可以理解成我们在向一个文件流里写入数据。
另外需要注意,对于C语言程序,只要运行起来,就默认打开了3个流:
stdin——标准输入流(对应键盘)
stdout——标准输出流(对应屏幕)
stderr——标准错误流(对应屏幕)
这3个流的类型都为 FILE* 型的流的文件指针。

字符输入输出函数 —— fgetc 与 fputc

fputc函数


函数的功能为向一个流中写入字符,该函数的返回类型为 int 型,对于返回值,有如下描述:

即当函数写入字符成功,则返回字符相应的ASCII码值,当写入失败,则返回EOF。
例如:
将字符‘a’、‘b’、‘c’写入到标准输出流

通过函数将字符写入到屏幕。

再例如:

#include<stdio.h>
#include<string.h>
int main()
{//创建并打开文件FILE* pf = fopen("test.txt", "w");//以读的方式打开文件//注:若文件中原本就有test.txt文件,则不用再创建了,若没有,则将会先创建该文件后再以相应的方式打开文件if (pf == NULL){perror("fopen");return 1;}int i = 0;for (i = 'a'; i <= 'z'; i++){fputc(i, pf);//运用循环将字符a~z写入到文件流中}fclose(pf);//关闭文件pf = NULL;return 0;
}

当程序运行完成后,打开文件路径就可以看到我们在程序中创建的文件,用记事本打开后就能看见文件中的内容,如下:

fgetc函数


该函数的功能为从流中读取一个字符,返回类型如fputc一样(不多说明)
例如:
首先在相应的文件路径下创建一个文件如下:

#include<stdio.h>
#include<string.h>
int main()
{FILE* pf = fopen("test1.txt", "r");//以读的方式打开文件if (pf == NULL){perror("fopen");return 1;}int ret=fgetc(pf);//从标准输入流中获取字符printf("%c\n", ret);//打印该字符,下同ret = fgetc(pf);printf("%c\n", ret);ret = fgetc(pf);printf("%c\n", ret);fclose(pf);pf = NULL;return 0;
}


通过fgetc函数就可从文件流中获取字符,然后通过打印在屏幕上显示。

再例如:

即先在屏幕上输入字符,然后函数在从屏幕上获取字符。
需要注意的是,无论是从屏幕上还是从文件中获取字符,当函数运行一次后,流(标准输入流或者文件流)的指针就会向后移动一步,所以函数运行一次字符就会依次打印出来。

文本行输入输出函数 —— fgets 与 fputs

fputs函数


该函数的功能是将一个字符串写入到一个流中,函数的第一个参数为被写入的字符串(首地址),第二个参数为一个流,函数的返回值为 int 型,当函数写入成功,则返回一个正数,当写入失败,则返回EOF。
例如:

#include<stdio.h>
#include<string.h>
int main()
{FILE* pf = fopen("data.txt", "w");if (pf == NULL){perror("fopen");return 1;}char arr[] = "Hello world!";fputs(arr, pf);fclose(pf);pf = NULL;return 0;
}


可见该文件打开成功且字符串写入成功!
当要写入字符串到屏幕上时如下(类似于fputc的运用):

fgets函数


该函数的功能为从流中读取一个字符串到相应的存储位置;第一个参数为获取到字符串的存储的位置,第二个参数为要读取的字符串的个数(也可称为要读取的字节数),第三个参数为要读取文件的文件指针(文件流),若函数读取成功,则返回储存字符串位置的地址,如果读取过程中发生错误,或是读取到了文件末尾,则返回一个空指针(NULL) 。
如下:
首先创建一个文件

#include<stdio.h>
#include<string.h>
int main()
{FILE* pf = fopen("data1.txt", "r");//以读的方式打开文件if (pf == NULL){perror("fopen");return 1;}char arr[20] = { 0 };fgets(arr, 5, pf);//将文件中的字符串读入到arr中//注:这里读取的为5个字节,其中包含字符'\0'printf("%s\n", arr);//打印出读取后的字符串fclose(pf);pf = NULL;return 0;
}


当要从屏幕上读取(即标准输入流)则类似于fgetc,如下:

格式化输入输出函数 —— fscanf 与 fprintf

fprintf函数


该函数的功能为将格式化的数据写入到目标流中,函数的第一个参数为一个文件流,即数据写入的目标流,第二个参数看似比较复杂,但是没关系,我们可以以另一个函数做类比,即将该函数以printf函数的参数做对比,如下:

我们对 printf 函数并不陌生,所以我们在这里可以类比出 fprintf 的参数形式。
举个栗子:
我们要将一个结构体类型的变量信息输出到data.txt文件中去

#include<stdio.h>
#include<string.h>
struct S
{char name[20];int age;char sex[5];
};
int main()
{FILE* pf = fopen("data.txt", "w");if (pf == NULL){perror("fopen");return 1;}struct S s = { "张三",18,"男" };fprintf(pf, "%s %d %s", s.name, s.age, s.sex);fclose(pf);pf = NULL;return 0;
}


可见该结构体写入文件成功。

所以我们可见 fprintf 函数的功能就是将 “区域一”中的数据以 “区域二” 的格式写入到 “区域一”,如下:

fscanf函数


当我们熟悉 fprintf 函数后就会很容易理解 fscanf 函数,在与scanf函数进行对比如下,我们可知该函数的第二个参数与 scanf 函数的参数一样。

举个栗子:
我们首先创建一个文档

#include<stdio.h>
#include<string.h>
struct S
{char name[20];int age;char sex[5];
};
int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){perror("fopen");return 1;}struct S s = { 0 };fscanf(pf, "%s %d %s", s.name, &s.age, s.sex);printf("%s %d %s\n", s.name, s.age, s.sex);fclose(pf);pf = NULL;return 0;
}


可见通过fscanf函数能够读取文件中的数据,所以我们可以知道:

fscanf函数的功能就是将 “区域一” 中的数据以 “区域二” 的格式读取到 “区域三” 中。

扩展(函数对比)

对比以下两组函数:
scanf / fscanf / sscanf
printf / fprintf / sprintf

这里我们首先讲解一下 sscanf 函数与 sprintf 函数。

对于sprintf函数,原型如下:

根据文档解释我们可知该函数能够将一个格式化的数据以字符串的形式写入到目标地址 buffer 中,该函数的第一个参数为转换为字符串的目标地址,第二个参数参考 fprintf 或 printf 函数(三者的此参数一样)。
栗子如下:

struct S
{char name[20];int age;char sex[5];
};
int main()
{struct S s = { "张三",18,"男" };char buf[100] = { 0 };sprintf(buf, "%s %d %s", s.name, s.age, s.sex);//将结构体s中的数据以字符串的形式写入到buf中printf("%s\n", buf);return 0;
}


可见结果为将结构体 s 中的数据以字符串的形式写入到 buf 中。

对于sscanf函数,原型如下:

该函数的功能是能够从字符串 ( buffer ) 中读取格式化的数据,第一个参数为被读取字符串的地址,第二个参数参考fscanf或scanf函数。
应用如下:

struct S
{char name[20];int age;char sex[5];
};
int main()
{struct S s = { "张三",18,"男" };char buf[100] = { 0 };sprintf(buf, "%s %d %s", s.name, s.age, s.sex);printf("%s\n", buf);printf("\n");struct S s1 = { 0 };sscanf(buf, "%s %d %s", s1.name, &(s1.age), s1.sex);//将字符串buf中的数据读取到结构体s1中printf("%s %d %s", s1.name, s1.age, s1.sex);return 0;
}


总结:
scanf——针对标准输入(stdin)的格式化输入语句
fscanf——针对所有输入流(stdin/文件)的格式化输入语句
sscanf——从一个字符串中读取一个格式化的数据

printf——针对标准输出(stdout)的格式化输出语句
fprintf——针对所有输出流(stdout/文件)的格式化输出语句
sprintf——把一个格式化的数据,转换为字符串

二进制输入输出函数 —— fread与 fwrite

fwrite函数

函数的原型为:

对于参数,文档给出如下解释;

即第一个参数为一个指针,即函数输入数据的位置,第二个参数为字节数,第三个参数为要写入的元素个数,第四个参数为数据写入的目标位置,即目标流。
所以我们可以看出该函数的功能就是能将最多 count 个 size 字节大小的 buffer 地址的数据写入到目标 stream 中。
例如

#include<stdio.h>
#include<string.h>
struct S
{char arr[20];int x;float y;
};
int main()
{FILE* pf = fopen("data.txt", "w");if (pf == NULL){perror("fopen");return 1;}struct S s = {"abcdef",12,5.5f};fwrite(&s, sizeof(struct S), 1, pf);//写入数据到结构体s中fclose(pf);pf = NULL;return 0;
}


可见,此时的文件中是有内容的,但是电脑是以二进制的形式写入的,只是我们看不懂。

fread函数

函数原型:

该函数也是4个参数,参数的意义与 fwrite 函数的参数类似,不同的是该函数的功能是从 stream 中获取最多 count 个 size 字节大小的数据到 buffer 地址中。
例如:
我们在fwrite函数的讲解中已经在data.txt文件中写入数据,接下来我们再将data.txt中的数据读读取出来并打印在屏幕上

struct S
{char arr[20];int x;float y;
};
int main()
{struct S s = { 0 };FILE* pf = fopen("data.txt", "r");if (pf == NULL){perror("fopen");return 1;}fread(&s, sizeof(struct S), 1, pf);//从pf中读取数据到s中printf("%s %d %f\n", s.arr, s.x, s.y);fclose(pf);pf = NULL;return 0;
}


可见函数从文件中以二进制的形式读取成功。

文件的随机读写

fseek函数

该函数原型:

函数的功能为将含函数指针移动到一个特定的位置;该函数的第一个参数是要移动位置的文件指针,第二个参数是文件指针经操作后相对于这个“起始位置”的偏移量,第三个参数是“初始位置”(并非文件信息区的起始位置),单位为字节。对于返回值,fseek函数如果调用成功,则返回0;若调用失败,则返回一个非0的值。
对于该函数的第三个参数 origin 有如下三种形式:

参数形式 表示意义
SEEK_CUR 文件指针的当前位置
SEEK_SET 文件开头
SEEK_END 文件末尾

应用举例:
我们先在data.txt 文件中写入“Hello world!”

为了使文件指针移动三次我们这样操作:

int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){perror("fopen");return 1;}int i = 0;for (i = 0; i < 7; i++){fgetc(pf);}fclose(pf);pf = NULL;return 0;
}

此时文件指针pf指向了字符串中的字符 ‘w’ 。
如果我们要读取 data.txt 文件中的字符 ‘r’ ,则有三种方式:

1.让文件指针相对于其当前位置向后偏移2个字节

 fseek(pf, 2, SEEK_CUR);//调整文件指针位置,即从字符‘w’的位置向后偏移2个单位,文件指针就指向了字符‘r’

2.让文件指针相对于文件开头偏移9个字节(即指向文件开头)

fseek(pf, 9, SEEK_CUR);

3.让文件指针相对于文件末尾向前偏移3个字节

fseek(pf, -3, SEEK_END);

经过这三种方法均可使文件指针指向特定的位置。

ftell函数

为了更好地明确文件指针位于什么位置,于是出现了ftell函数,它用于计算当前文件指针相对于起始位置的偏移量。函数原型如下:

函数的参数就为文件指针,当函数运行成功时,返回文件指针文件指针相对于文件起始位置的偏移量,若运行失败,则返回 -1 。
例如:

上述代码首先利用fseek函数使文件指针从起始位置向后偏移5个单位,在利用ftell函数求出函数的偏移量为5。

rewind函数

函数原型为:

该函数的功能为使文件指针 stream 返回到起始位置。
例如:

当文件向后偏移,然后在利用rewind函数使指针指向起始位置,利用fgetc函数打印出第一个字符。

文件读取结束的判定

牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。
1 . 文本文件读取是否结束,判断返回值是是否为 EOF( fgetc ),或者 NULL( fgets )。
例如:
fgetc 判断是否为 EOF .
fgets 判断返回值是否为 NULL

正确的使用:
文本文件的例子如下

int main(void)
{int c;//注意是int,非char,要求处理EOFFILE*fp=fopen("text.txt","r");if(!fp){perror("File opening failed");return EXIT_FAILURE;}//fgetc当读取失败或者遇见文件结束的时候,都会返回EOFwhile((c=fgetc(fp))!=EOF){putchar(c);}//判断是什么原因结束的if(ferror(fp))puts("读取失败");else if(feof(fp))puts("遇见文件结尾了");fclose(fp);
}

对于文件操作的详解到此结束!

一次性就能学会的文件操作!(文件操作函数详解)相关推荐

  1. linux 系统函数调用脚本文件,Linux系统调用fsync函数详解

    Linux系统调用fsync函数详解 发布时间:2013-11-14 19:55:10   作者:佚名   我要评论 Linux fsync函数主要用于将同步内存中所有已修改的文件数据到储存设备,多用 ...

  2. Python基本语法_文件操作_读写函数详解

    目录 目录 软件环境 file文件对象 open文件操作 读文件 read读取所有文件内容 readline获取一行内容 readlines读取所有文件内容 readreadlinereadlines ...

  3. API读取写入 ini文件内容的方法函数详解

    ini文件(即Initialization file),这种类型的文件中通常存放的是一个程序的初始化信息.ini文件由若干个节(Section)组成,每个Section由若干键(Key)组成,每个Ke ...

  4. Python操作文件之open函数详解

    Python的open函数详解 open(file, mode='rt', encoding=None) -> BaseIO mode参数详解: 字符 含意 'r' 读取(默认) 'w' 写入, ...

  5. python open写入_Python3 open() 函数详解 读取文件写入文件追加文件二进制文件

    Python3 open() 函数详解 读取文件写入文件追加文件二进制文件 open()函数的主要作用是打开文件并返回相应文件对象,使用文件对象可以对当前文件进行读取.写入.追加等操作,默认情况下&q ...

  6. Linux用户、权限及改变文件所有者及文件所属组多例详解 附python代码

    https://blog.csdn.net/hanhanwanghaha宝藏女孩 欢迎您的关注! 欢迎关注微信公众号:宝藏女孩的成长日记 如有转载,请注明出处(如不注明,盗者必究) Linux用户.权 ...

  7. python修改xml标签的值_对python修改xml文件的节点值方法详解

    这是我的xml文件结构 <?xml version='1.0' encoding='utf-8'?> JPEGImages train_2018-05-08_1000.jpg D:\all ...

  8. python对文件的处理_python文件处理fileinput使用方法详解

    这篇文章主要介绍了python文件处理fileinput使用方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.介绍 fileinput模块 ...

  9. linux mv复制命令,linux中删除复制移动文件rm,mv,cp命令详解linux操作系统 -电脑资料...

    在linux中对文件的复制删除移动分别会使用到rm,mv,cp三个命令,下面我来给大家介绍一下rm,mv,cp命令对文件的常规操作吧, 先看实例 删除复制移动文件命令 Linux代码 rm -rf / ...

  10. 制作可执行的JAR文件包及jar命令详解

    制作可执行的JAR文件包及jar命令详解zt http://www.chinaunix.net 作者:郝君  发表于:2003-08-12 14:32:38 常常在网上看到有人询问:如何把 java  ...

最新文章

  1. 2019年北航OO第四单元(UML任务)及学期总结
  2. 035_使用Enumeration遍历Vector元素
  3. paddlepaddle系列之三行代码从入门到精通
  4. java input回车,用java怎样编写加减乘除,从键盘输入,例如:1+2按回车得到
  5. ife 零基础学院 day 2
  6. 让机器也拥有品味!时尚图像补全网络FiNet| ICCV 2019 Oral
  7. PyTorch 1.0 中文文档:torchvision.models
  8. 剑指offer:斐波那契数列
  9. Latent Semantic Analysis (LSA) Tutorial第一部分(转载)
  10. ubuntu系统无法连接识别到adb设备和fastboot设备解决方法
  11. PHP静态方法中调用非静态方法
  12. 公有云Docker镜像P2P加速之路:安全篇
  13. 处理python SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: trun
  14. 关于家里的宽带和无线wifi路由器的一些选择和配置
  15. 2021-03-10
  16. WIN10设置自启动脚本
  17. win10定时关机怎么设置(Win10怎么设置亮度)
  18. 使用Intel NCS2 算力棒 安装部署记录Windows 10, Intel openvino_toolkit_p_2019.1.148
  19. 新走遍美国第一遍总结
  20. 我的世界服务器物品栏变小了,我的世界如何改变物品大小 | 手游网游页游攻略大全...

热门文章

  1. 渐变马赛克——水晶格图标
  2. 如何成为月入5W的 IT 人?
  3. MySQL中group_concat函数用法总结
  4. js pdf转html在线转换,使用pdf2htmlEX实现将pdf转html
  5. 安装FreeBSD release13.0教程
  6. vscode高逼格敲代码特效
  7. 区块链是个噱头吗?麦腾:可以帮助经济体系
  8. orange安装教程
  9. spring-webflux中FluxDataBuffer 转String
  10. Apache Hive DML语句与函数使用