当前位置: 首页 > news >正文

C语言使用技巧(二十九):回顾fopen,fwrite,fread,fseek,fclose,ftell,fputs,gets,rewind,fprintf函数用法

FILE文件流用于对文件的快速操作,主要的操作函数有fopen、fseek、fread、fclose,在对文件结构比较清楚时使用这几个函数会比较快捷的得到文件中具体位置的数据,提取对我们有用的信息,满足编程中的需要。以下分别进行说明,还有他们使用时的注意事项。

目录

  • 1、fopen
  • 2、fread 与 fwrite
  • 3、fseek
  • 4、fclose
  • 5、ftell
  • 6、fputs\puts与gets
  • 7、fwrite
  • 8、rewind 函数
  • 9、fprintf
  • 参考

1、fopen

函数原型 FILE * fopen(const char *path,cost char *mode)

作用:打开一个文件,返回指向该文件的指针

参数说明:第一个参数为欲打开文件的文件路径及文件名,第二个参数表示对文件的打开方式

注:mode有以下值:

r:只读方式打开,文件必须存在

r+:可读写,必须存在

rb+:打开二进制文件,可以读写

rt+:打开文本文件,可读写

w:只写,文件存在则文件长度清0,文件不存在则建立该文件

w+:可读写,文件存在则文件长度清0,文件不存在则建立该文件

a:附加方式打开只写,不存在建立该文件,存在写入的数据加到文件尾,EOF符保留

a+:附加方式打开可读写,不存在建立该文件,存在写入的数据加到文件尾,EOF符不保留

wb:打开二进制文件,只写

wb+:打开或建立二进制文件,可读写

wt+:打开或建立文本文件,可读写

at+:打开文本文件,可读写,写的数据加在文本末尾

ab+:打开二进制文件,可读写,写的数据加在文件末尾

由mode字符可知,上述如r、w、a在其后都可以加一个b,表示以二进制形式打开文件

返回值:文件打开了,返回一个指向该打开文件的指针(FILE结构);文件打开失败,错误上存error code(错误代码)

注意:在fopen操作后要进行判断,是否文件打开,文件真正打开了才能进行后面的读或写操作,如有错误要进行错误处理

例:FILE *pfile=fopen(const char *filename,“rb”);

打开文件流还有一个支持宽字符的函数,如下

FILE *_wfopen(const wchar_t *filename,const wchar_t *mode)

代码demo实现:

#include <stdio.h>
#define N 100
int main(int argc, char *argv[])
{
    int filesize;
    char str[N + 1];

    FILE *fp = fopen("hello.txt","rb");
    if(fp == NULL)
    {
        perror("open error");
        return -1;
    }
    //循环读取文件的每一行数据
    while( fgets(str, N, fp) != NULL ) {
        printf("打印文件数据txt_str------>:%s", str);
    }

    fseek(fp,0,SEEK_END);
    // fputs("Seagull Ali", fp);
    filesize = ftell(fp);

    printf("this file size is:%d byte!\n",filesize);
	
    fclose(fp);
    return 0;

}

/**
 * 语法:int fseek(FILE *stream, long int offset, int whence)

参数

第一个参数 stream 为文件指针
第二个参数 offset 为偏移量,整数表示正向偏移,负数表示负向偏移
第三个参数 whence 设定从文件的哪里开始偏移,可以使用3个常量之一,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET
SEEK_SET  -  文件开头
SEEK_CUR  -  当前位置
SEEK_END  -  文件结尾

其中SEEK_SET,SEEK_CUR 和 SEEK_END也可以依次使用为 0,1 和 2表示。

fputs(str, stdout);  //将字符数组的内容输出到输出流stdout中
fgets(str, 19, stdin);  /*从输入流stdin中读取19个字符到字符数组str中*/


执行结果:

gcc file_c.c -o file_c && ./file_c
打印文件数据txt_str------>:r:只读方式打开,文件必须存在
打印文件数据txt_str------>:r+:可读写,必须存在
打印文件数据txt_str------>:rb+:打开二进制文件,可以读写
打印文件数据txt_str------>:rt+:打开文本文件,可读写
打印文件数据txt_str------>:w:只写,文件存在则文件长度清0,文件不存在则建立该文件 
打印文件数据txt_str------>:w+:可读写,文件存在则文件长度清0,文件不存在则建立该文件this file size is:314 byte!

其中hello.txt文件数据内容为:

r:只读方式打开,文件必须存在
r+:可读写,必须存在
rb+:打开二进制文件,可以读写
rt+:打开文本文件,可读写
w:只写,文件存在则文件长度清0,文件不存在则建立该文件 
w+:可读写,文件存在则文件长度清0,文件不存在则建立该文件

2、fread 与 fwrite

函数原型:size_t fread(void* buff,size_t size,size_t count,FILE* stream)

作用:从文件中读入数据到指定的地址中

参数:第一个参数为接收数据的指针(buff),也即数据存储的地址

第二个参数为单个元素的大小,即由指针写入地址的数据大小,注意单位是字节

第三个参数为元素个数,即要读取的数据大小为size的元素个素

第四个参数为提供数据的文件指针,该指针指向文件内部数据

返回值:读取的总数据元素个数

例:

int  num,count;

int* pr=new int[num*count];

fread(pr, num*4, count, stream);   // stream为fopen中返回的FILE指针

要将数据写入pr中,必须为pr分配内存,一个int为4个字节,所以要x4。

再次解释:

read(buffer,size,count,fp);   用来读入一个数据块
fwrite(buffer,size,count,fp); 用来写入一个数据块

参数说明:
(1)buffer:是一个指针,对fread来说,它是读入数据的存放地址。对fwrite来说,是要输出数据的地址。
(2)size:要读写的字节数;
(3)count:要进行读写多少个size字节的数据项;
(4)fp:文件型指针。

举例:
1.fread(&id,1,10,f)就是把f里面的值读到id里面,每次读1个字节,一共读10次,或者把id里面的值都读完,不到10次也会停止。
2.fwrite(&id,1,10,f)就是把id里面的值写到f里面,每次读1个字节,一共读10次或是fwrite(&id,10,1,f)就是把id里面的值写到f里面,每次写10个字节,一共写1次。

3、fseek

函数原型:int fseek(FILE *stream,long offset,int framewhere)
作用:重定位文件内部的指针
参数:第一个为文件指针,第二个是指针的偏移量,第三个是指针偏移起始位置
返回值:重定位成功返回0,否则返回非零值
需要注意的是该函数不是重定位文件指针,而是重定位文件内部的指针,让指向文件内部数据的指针移到文件中我们感兴趣的数据上,重定位主要是这个目的。
说明:执行成功,则stream指向以fromwhere为基准,偏移offset个字节的位置。执行失败(比方说offset偏移的位置超出了文件大小),则保留原来stream的位置不变

简言之:
  fseek(fp,100L,0);把文件内部 指针 移动到离文件开头100字节处;
  fseek(fp,100L,1);把文件内部 指针 移动到离文件当前位置100字节处;
  fseek(fp,-100L,2);把文件内部 指针 退回到离文件结尾100字节处。
示例:
fseek(fp, 0L, SEEK_END);
解释:文件指针定位到文件末尾,偏移0个字节

代码实现案例:
最初程序创建文件和写入 This is runoob.com,但是之后我们在第七个位置重置了写指针,并使用 puts() 语句来重写文件。

#include <stdio.h>

int main ()
{
   FILE *fp;

   fp = fopen("./file2.txt","w+");
   fputs("This is runoob.com 2022", fp);
  
   fseek( fp, 7, SEEK_SET );
   fputs(" C Programming Langauge", fp);
   fclose(fp);
   
   return(0);
}

执行结果:file2.txt

This is C Programming Langauge

4、fclose

函数原型:int fclose(FILE *stream)

功能:关闭一个文件流,使用fclose就可以把缓冲区内最后剩余的数据输出到磁盘文件中,并释放文件指针和有关的缓冲区

熟练使用以上函数可以从文件中获取对我们有用的数据型,前提对于文件格式很了解,比如,对于一个DIB位图文件,就可以读取出他的文件中的头信息和像素点信息。

5、ftell

返回文件当前指针指向位置,与fseek配合可以算出文件元素数据总数。ftell()函数返回指定流的当前文件指针的位置。在文件末尾移动文件指针后,我们可以使用 ftell()函数获取文件的总大小。可以使用 SEEK_END常量来将文件指针移动文件末尾。
ftell()函数的语法:

long int ftell(FILE *stream)
#include <stdio.h>  

void main() {
    FILE *fp;
    int length;

    fp = fopen("file.txt", "r");
    fseek(fp, 0, SEEK_END);

    length = ftell(fp);

    fclose(fp);
    printf("Size of file: %d bytes", length);

}

执行结果:

Size of file: 67 bytes

6、fputs\puts与gets

fputs(str, stdout); //将字符数组的内容输出到输出流stdout中
gets(str, 19, stdin); /从输入流stdin中读取19个字符到字符数组str中/

fputs() 和 puts() 有两个小区别:
puts() 只能向标准输出流输出,而 fputs() 可以向任何流输出。
使用 puts() 时,系统会在自动在其后添加换行符;而使用 fputs() 时,系统不会自动添加换行符。

那么这是不是意味着使用 fputs() 时就要在后面添加一句“printf("\n");”换行呢?看情况!如果输入时使用的是 gets(),那么就要添加 printf 换行;但如果输入时用的是 fgets(),则不需要。

因为使用 gets() 时,gets() 会将回车读取出来并丢弃,所以换行符不会像 scanf 那样被保留在缓冲区,也不会被 gets() 存储;而使用 fgets() 时,换行符会被 fgets() 读出来并存储在字符数组的最后,这样当这个字符数组被输出时换行符就会被输出并自动换行。

但是也有例外,比如使用 fgets() 时指定了读取的长度,如只读取 5 个字符,事实上它只能存储 4 个字符,因为最后还要留一个空间给 ‘\0’,而你却从键盘输入了多于 4 个字符,那么此时“敲”回车后换行符就不会被 fgets() 存储。数据都没有地方存放,哪有地方存放换行符呢!此时因为 fgets() 没有存储换行符,所以就不会换行了。

# include <stdio.h>
int main(void)
{
    char str[20];  /*定义一个最大长度为19, 末尾是'\0'的字符数组来存储字符串*/
    printf("请输入一个字符串:");
    fgets(str, 19, stdin);  /*从输入流stdin中读取19个字符到字符数组str中*/
    fputs(str, stdout);  //将字符数组的内容输出到输出流stdout中
    return 0;
}

输出结果是:

请输入一个字符串:i love you
i love you
Press any key to continue

我们看到读取 19 个字符足够存储“i love you”,所以 fgets() 最后会存储换行符。这样 fputs() 输出时这个换行符就能换行了。
将读取的字符改小一点看看:

# include <stdio.h>
int main(void)
{
    char str[20];  /*定义一个最大长度为19, 末尾是'\0'的字符数组来存储字符串*/
    printf("请输入一个字符串:");
    fgets(str, 5, stdin);  //从输入流stdin中读取4个字符到字符数组str中
    fputs(str, stdout);  //将字符数组的内容输出到输出流stdout中
    return 0;
}

输出结果是:

请输入一个字符串:i love you
i loPress any key to continue

我们看到并没有换行。

值得说明的是,虽然 gets()、fgets()、puts()、fputs() 都是字符串处理函数,但它们都包含在 stdio.h 头文件中,并不是包含在 string.h 头文件中。

C 库函数 int fputs(const char *str, FILE *stream) 把字符串写入到指定的流 stream 中,但不包括空字符。
声明:
下面是 fputs() 函数的声明。
int fputs(const char *str, FILE *stream)
参数:
str – 这是一个数组,包含了要写入的以空字符终止的字符序列。
stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。
返回值:
该函数返回一个非负值,如果发生错误则返回 EOF。

#include <stdio.h>

int main ()
{
   FILE *fp;

   fp = fopen("file.txt", "w+");

   fputs("2022这是 C 语言。", fp);
   fputs("2022这是一种系统程序设计语言。", fp);

   fclose(fp);
   
   return(0);
}

执行结果在file.txt文件内:没有换行

2022这是 C 语言。2022这是一种系统程序设计语言。

加入换行即可变成:

   fputs("2022这是 C 语言。\n", fp);
   fputs("2022这是一种系统程序设计语言。\n", fp);

结果是:

2022这是 C 语言。
2022这是一种系统程序设计语言。

现在查看上面的内容:

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;

   fp = fopen("./file.txt","r");
   while(1)
   {
      c = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", c);
   }
   fclose(fp);
   return(0);
}

执行结果:

gcc readtxt.c -o readtxt && ./readtxt
2022这是 C 语言。
2022这是一种系统程序设计语言。

其中注意:
使用 feof 函数来替换 EOF 宏检测文件是否结束。当然,在用 feof 函数检测文件是否结束的同时,也需要使用 ferror 函数来检测文件读取操作是否出错,当 ferror 函数返回为真时就表示有错误发生。在实际的程序中,应该每执行一次文件操作,就用 ferror 函数检测是否出错。
函数 feof 只用于检测流文件,当文件内部位置指针指向文件结束时,并未立即置位 FILE 结构中的文件结束标记,只有再执行一次读文件操作,才会置位结束标志,此后调用 feof 才会返回为真。参考:http://c.biancheng.net/view/382.html

7、fwrite

描述:C 库函数 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 把 ptr 所指向的数组中的数据写入到给定流 stream 中。

声明:下面是 fwrite() 函数的声明。

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

参数:

ptr -- 这是指向要被写入的元素数组的指针。
size -- 这是要被写入的每个元素的大小,以字节为单位。
nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。


返回值:
如果成功,该函数返回一个 size_t 对象,表示元素的总数,该对象是一个整型数据类型。如果该数字与 nmemb 参数不同,则会显示一个错误。
代码实现:

#include<stdio.h>
 
int main ()
{
   FILE *fp;
   char str[] = "This is 2022 ";
 
   fp = fopen( "./file3.txt" , "w" );
   fwrite(str, sizeof(str) , 1, fp );
 
   fclose(fp);
  
   return(0);
}

其他:fwrite 和 fread函数的用法小结

8、rewind 函数

让文件指针的位置回到文件的起始位置。
void rewind(FILE*stream)
和fseek 的fseek(fp,0,SEEK_SET),相似。

#include <stdio.h>

int main()
{
	int n = 0;
	FILE* fp;
	char buffer[27];
	fp = fopen("myfile.txt", "w+");//原始内容被清除
	if (fp == NULL)
	{
		perror("Error opening file");
	}
	else
	{
		for (n = 'A'; n <= 'Z'; n++)
		{
			fputc(n, fp);//写完之后文件指针在文件末尾
		}
		rewind(fp);//文件指针在文件初始位置
		fread(buffer, 1, 26, fp);
		//从fp文件中读取26的大小为1字节的数据,放到buffer中
	}
	fclose(fp);
	buffer[26] = '\0';
	puts(buffer);//buffer打印在显示器上
	return 0;
}

结果是txt文件的26个字母。

9、fprintf

描述:C 库函数 int fprintf(FILE *stream, const char *format, …) 发送格式化输出到流 stream 中。

声明:下面是 fprintf() 函数的声明。

int fprintf(FILE *stream, const char *format, …)
参数:
stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
format – 这是 C 字符串,包含了要被写入到流 stream 中的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier。

#include <stdio.h>
#include <stdlib.h>

int main()
{
   FILE * fp;

   fp = fopen ("file.txt", "w+");
   fprintf(fp, "%s %s %s %d", "We", "are", "in", 2014);
   
   fclose(fp);
   
   return(0);
}

输出结果写入了txt文件。

C语言fscanf和fprintf函数的用法详解(格式化读写文件):http://c.biancheng.net/view/2073.html
c语言中fprintf函数_C语言中的fprintf()函数与示例:https://blog.csdn.net/cumt30111/article/details/107799919
https://www.runoob.com/cprogramming/c-function-fprintf.html添加链接描述

参考

https://blog.csdn.net/cffy625/article/details/59148605
http://c.biancheng.net/view/238.html

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 桌面端的移动运算(三)
  • C语言使用技巧(三十):计算程序运行时间以及自带的函数库calcElapsed(startTime, now())
  • 桌面端的移动计算(四)
  • C/C++音频算法: noise suppression算法及技术资料汇总
  • 经济观察报:新浪打造网络新闻的工业化实验
  • AI模型设计:C++实现深度学习神经网络模型及源码分享
  • C语言使用技巧(三十一):回顾strlen函数简单使用
  • 导航界面
  • python使用技巧(二十七):音频WAV和PCM的互相转换
  • Java学习备忘录(一)安装篇(原创)
  • C语言使用技巧(三十二):读写txt文件指定行指定所有行类型数据
  • AI模型设计:安装C++版本的libtensorflow(1.10~2.6.0)以及TFC++ demo源码的实现
  • 酒店管理(链表和文件操作)
  • AI模型设计:配置C++版本pytorch(libtorch 1.12)开发环境以及demo源码的实现
  • 2004年6月22日
  • JavaScript 如何正确处理 Unicode 编码问题!
  • codis proxy处理流程
  • Docker: 容器互访的三种方式
  • ES6系列(二)变量的解构赋值
  • Sequelize 中文文档 v4 - Getting started - 入门
  • 多线程 start 和 run 方法到底有什么区别?
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 深入 Nginx 之配置篇
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • 我感觉这是史上最牛的防sql注入方法类
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • ​Redis 实现计数器和限速器的
  • # 数仓建模:如何构建主题宽表模型?
  • (0)Nginx 功能特性
  • (4.10~4.16)
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (差分)胡桃爱原石
  • (机器学习-深度学习快速入门)第三章机器学习-第二节:机器学习模型之线性回归
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (九)信息融合方式简介
  • (十一)手动添加用户和文件的特殊权限
  • (数据结构)顺序表的定义
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (译)2019年前端性能优化清单 — 下篇
  • (转)jdk与jre的区别
  • (自用)仿写程序
  • *** 2003
  • ***详解账号泄露:全球约1亿用户已泄露
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .xml 下拉列表_RecyclerView嵌套recyclerview实现二级下拉列表,包含自定义IOS对话框...
  • //TODO 注释的作用
  • /var/log/cvslog 太大
  • @Responsebody与@RequestBody
  • [\u4e00-\u9fa5] //匹配中文字符
  • [17]JAVAEE-HTTP协议
  • [2024-06]-[大模型]-[Ollama]- WebUI
  • [C++]拼图游戏