C语言入门篇——文件操作篇

这篇具有很好参考价值的文章主要介绍了C语言入门篇——文件操作篇。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1、为什么使用文件

2、什么是文件

2.1程序文件

2.2数据文件

2.3文件名

3、文件的打开和关闭

3.1文件指针

3.2文件的打开和关闭

4、文件的顺序读写

5、文件的随机读写

5.1fseek

5.2ftell

5.3rewind

6、文本文件和二进制文件

7、文件读取结束的判定

8、文件缓冲区


1、为什么使用文件

程序的数据是存放在内存中,当程序退出的时候,程序的数据自然就不存在了,等下一次运行我们的程序就需要重新输入自己的数据,这样就比较麻烦。数据持久化的方法一般有:吧数据存放在错案文件和存放到数据库等方式,我们使用文件的时候就可以把数据直接存放到电脑的硬盘上,做到了数据了持久化。

2、什么是文件

文件(file)通常是在磁盘或固态硬盘上的一段已命名的存储区。对我 们而言,stdio.h就是一个文件的名称,该文件中包含一些有用的信息。然 而,对操作系统而言,文件更复杂一些。例如,大型文件会被分开储存,或 者包含一些额外的数据,方便操作系统确定文件的种类。然而,这都是操作 系统所关心的,程序员关心的是C程序如何处理文件。

C把文件看作是一系列连续的字节,每个字节都能被单独读取。C提供两种文件模式:文本模式和二进制模式。

要区分文本内容和二进制内容、文本文件格式和二进制文件格 式,以及文件的文本模式和二进制模式。

所有文件的内容都以二进制形式(0或1)储存。但是,如果文件最初使用二进制编码的字符表示文本,该文件就是文本文件,其中包含文本内容。如果文件中的二进制值代表机器语言代码或数值数据或图片或音乐编码,该文件就是二进制文件,其中包含二进制内容。

为了规范文本文件的处理,C 提供两种访问文件的途径:二进制模式和 文本模式。在二进制模式中,程序可以访问文件的每个字节。而在文本模式 中,程序所见的内容和文件的实际内容不同。程序以文本模式读取文件时, 把本地环境表示的行末尾或文件结尾映射为C模式。

除了以文本模式读写文本文件,还能以二进制模式读写文本文件。

在程序设计中,我们一般谈的文件有两种:程序文件、数据文件。

2.1程序文件

包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境 后缀为.exe)。

2.2数据文件

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

2.3文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。

文件名包含3部分:文件路径+文件名主干+文件后缀,例如:D:\资料\vs\test

为了方便起见,文件标识常被称为文件名。

3、文件的打开和关闭

3.1文件指针

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

struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
       };
typedef struct _iobuf FILE;

 不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。 每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息, 使用者不必关心细节。 一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

FILE* pf = NULL;

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

C语言入门篇——文件操作篇

3.2文件的打开和关闭

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。 在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。 ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。

//打开文件
FILE* fopen(const char* filename,const char* mode);
函数作用:打开文件
参数:filename:文件名
    mode:文件使用方式
返回值:成功:文件流指针
        失败:NULL

//关闭文件
int fclose(FILE* stream);
函数作用:关闭文件
参数:stream:文件指针流
返回值:成功:0
        失败:EOF(-1)
文件打开方式
文件使用方式 含义 如果至指定文件不存在
“r”(只读) 为了输入数据,打开一个已经存在的文本文件 出错
“w”(只写) 为了输出数据,打开一个文本文件 建立一个新的文件
“a”(追加) 向文本文件尾添加数据 建立一个新的文件
“rb”(只读) 为了输入数据,打开一个二进制文件 出错
“wb”(只写) 为了输出数据,打开一个二进制文件 建立一个新的文件
“ab”(追加) 向一个二进制文件尾添加数据 出错
“r+”(读写) 为了读和写,打开一个文本文件 出错
“w+”(读写) 为了读和写,建议一个新的文件 建立一个新的文件
“a+”(读写) 打开一个文件,在文件尾进行读写 建立一个新的文件
“rb+”(读写) 为了读和写打开一个二进制文件 出错
“wb+”(读写) 为了读和写,新建一个新的二进制文件 建立一个新的文件
“ab+”(读写) 打开一个二进制文件,在文件尾进行读和写 建立一个新的文件

 C语言入门篇——文件操作篇

4、文件的顺序读写

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

 这里介绍fscanf,fprintf,fread,fwite四个函数。

fscanf() 和 fprintf() 函数与前面使用的 scanf() 和 printf() 功能相似,都是格式化读写函数,两者的区别在于 fscanf() 和 fprintf() 的读写对象不是键盘和显示器,而是磁盘文件。

函数原型如下:
int fscanf ( FILE *fp, char * format, ... );
int fprintf ( FILE *fp, char * format, ... );

函数参数:
fp 为文件指针;
format 为格式控制字符串;
... 表示参数列表;

fprintf() 返回成功写入的字符的个数,失败则返回负数
fscanf() 返回参数列表中被成功赋值的参数个数

与 scanf() 和 printf() 相比,它们仅仅多了一个 fp 参数

 两个函数的测试代码为:

int main(void)
{
	FILE* pf1 = NULL;
	pf1 = fopen("test.txt", "w");
	if (pf1 == NULL)
	{
		printf("打开文件失败\n");
		return -1;
	}

	char buf[1024] = "helloworld!";
	fprintf(pf1, "%s", buf);
	fclose(pf1);

	return 0;
}

int main(void)
{
	FILE* pf2 = NULL;

	pf2 = fopen("test.txt", "r");
	if (pf2 == NULL)
	{
		printf("打开文件失败\n");
		return -1;
	}

	char data[1024] = { 0 };
	int ret = fscanf(pf2, "%s", data);

	printf("ret:%d\n", ret);

	printf("data:%s\n", data);
	fclose(pf2);
	return 0;
}

 C语言入门篇——文件操作篇

 fread() 函数用来从指定文件中读取块数据。所谓块数据,也就是若干个字节的数据,可以是一个字符,可以是一个字符串,可以是多行数据,并没有什么限制。fread() 的原型为:

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

 fwrite() 函数用来向文件中写入块数据,它的原型为:

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

 对参数的说明:

  • ptr 为内存区块的指针,它可以是数组、变量、结构体等。fread() 中的 ptr 用来存放读取到的数据,fwrite() 中的 ptr 用来存放要写入的数据。
  • size:表示每个数据块的字节数。
  • count:表示要读写的数据块的块数。
  • fp:表示文件指针。
  • 理论上,每次读写 size*count 个字节的数据。

size_t 是在 stdio.h 和 stdlib.h 头文件中使用 typedef 定义的数据类型,表示无符号整数,也即非负数,常用来表示数量。

返回值:返回成功读写的块数,也即 count。如果返回值小于 count:

  • 对于 fwrite() 来说,肯定发生了写入错误,可以用 ferror() 函数检测。
  • 对于 fread() 来说,可能读到了文件末尾,可能发生了错误,可以用 ferror() 或 feof() 检测。

这两个函数的测试代码如下:

int main(void)
{
	FILE* pf1 = NULL;
	pf1 = fopen("test1.txt", "wb+");
	if (pf1 == NULL)
	{
		printf("打开文件失败\n");
		return -1;
	}

	char buf[1024] = { "hadhasio" };
	fwrite(buf, sizeof(buf), 1, pf1);
	fclose(pf1);

	return 0;
}

int main(void)
{
	FILE* pf2 = NULL;

	pf2 = fopen("test1.txt", "rb+");
	if (pf2 == NULL)
	{
		printf("打开文件失败\n");
		return -1;
	}

	char data[1024] = { 0 };
	int ret = fread(data, sizeof(data), 1, pf2);

	printf("ret:%d\n", ret);

	printf("data:%s\n", data);
	fclose(pf2);
	return 0;
}

5、文件的随机读写

5.1fseek

函数功能是把文件指针指向文件的开头,需要包含头文件stdio.h

函数原型:
int fseek(FILE *stream, long int offset, int whence)

参数:stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流
    offset -- 这是相对 whence 的偏移量,以字节为单位
    whence -- 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:

返回值:
如果成功,则该函数返回零,否则返回非零值。
常量 描述
SEEK_SET 文件的开头
SEEK_CUR 文件指针的当前位置
SEEK_END 文件的末尾

 测试代码如下:

int main()
{
	FILE* fp = NULL;

	fp = fopen("test.txt", "w+");
	if (fp == NULL)
	{
		printf("打开文件失败\n");
		return -1;
	}
	fputs("This is sakura0908", fp);

	fseek(fp, 7, SEEK_SET);
	fputs(" C Programming Langauge", fp);

	fclose(fp);

	return(0);
}

C语言入门篇——文件操作篇

5.2ftell

返回给定流 stream 的当前文件位置,需要包含头文件stdio.h

函数原型:
long int ftell(FILE *stream);

参数:stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流

返回值:该函数返回位置标识符的当前值。如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值

测试代码案例如下:

int main()
{
    FILE* fp = NULL;
    int len;

    fp = fopen("test.txt", "r");
    if (fp == NULL)
    {
        perror("打开文件错误");
        return(-1);
    }
    fseek(fp, 0, SEEK_END);

    len = ftell(fp);
    fclose(fp);

    printf("test.txt 的总大小 = %d 字节\n", len);

    return(0);
}

C语言入门篇——文件操作篇

5.3rewind

设置文件位置为给定流 stream 的文件的开头,需要包含头文件stdio.h

函数原型:
void rewind(FILE *stream);

参数:
stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流

返回值:
该函数不返回任何值

 测试代码案例如下:

int main()
{
   char str[] = "This is runoob.com";
   FILE *fp;
   int ch;

   /* 首先让我们在文件中写入一些内容 */
   fp = fopen( "file.txt" , "w" );
   fwrite(str , 1 , sizeof(str) , fp );
   fclose(fp);

   fp = fopen( "file.txt" , "r" );
   while(1)
   {
      ch = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", ch);
   }
   rewind(fp);
   printf("\n");
   while(1)
   {
      ch = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", ch);
     
   }
   fclose(fp);

   return(0);
}

 C语言入门篇——文件操作篇

6、文本文件和二进制文件

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。 数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。 如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文 本文件。 一个数据在内存中是怎么存储的呢? 字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。 如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而 二进制形式输出,则在磁盘上只占4个字节(VS2022测试)。

测试代码:

int main()
{
     int a = 10000;
     FILE* pf = fopen("test.txt", "wb");
     fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
     fclose(pf);
     pf = NULL;
     return 0;
}

7、文件读取结束的判定

牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。

而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。

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

例如: fgetc 判断是否为 EOF 或 fgets 判断返回值是否为 NULL .

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

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

int main(void)
{
    int c; // 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if (fp == NULL) 
    {
        perror("File opening failed");
        return -1;
    }
    //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
    {
        putchar(c);
    }

    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);

    return 0;
}

8、文件缓冲区

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

C语言入门篇——文件操作篇

 因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文 件。 如果不做,可能导致读写文件的问题。刷新缓冲区作用的函数有fflush函数和fclose函数

fflush函数:刷新缓冲区,某些编译器不支持,vs2022是不支持的。

fclsoe函数:关闭文件的时候,也会刷新缓冲区。文章来源地址https://www.toymoban.com/news/detail-432333.html

到了这里,关于C语言入门篇——文件操作篇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • spark底层为什么选择使用scala语言开发

    基于Scala的语言特性 集成性:Scala 是一种运行在 Java 虚拟机(JVM)上的静态类型编程语言,可以与 Java 代码无缝集成。由于 Spark 涉及到与大量 Java 生态系统的交互,例如 Hadoop、Hive 等,使用 Scala 可以方便地与这些组件进行集成和交互。 函数式编程支持:Scala 是一种面向函数

    2024年02月10日
    浏览(54)
  • AIGC基础:大型语言模型 (LLM) 为什么使用向量数据库,嵌入(Embeddings)又是什么?

    嵌入: 它是指什么?嵌入是将数据(例如文本、图像或代码)转换为高维向量的数值表示。这些向量捕捉了数据点之间的语义含义和关系。可以将其理解为将复杂数据翻译成 LLM 可以理解的语言。 为什么有用?原始数据之间的相似性反映在高维空间中对应向量之间的距离上。

    2024年02月21日
    浏览(56)
  • 【Golang】Golang进阶系列教程--为什么 Go 语言 struct 要使用 tags

    在 Go 语言中,struct 是一种常见的数据类型,它可以用来表示复杂的数据结构。在 struct 中,我们可以定义多个字段,每个字段可以有不同的类型和名称。 除了这些基本信息之外,Go 还提供了 struct tags,它可以用来指定 struct 中每个字段的元信息。 在本文中,我们将探讨为什

    2024年02月15日
    浏览(74)
  • Java开发手册中为什么不建议在for循环中使用“+“进行字符串操作

    java开发手册中对于循环体中进行字符串的拼接要求如下: 【推荐】循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。 说明:下例中,反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行 append操作, 最后通过 toString 方法返回

    2024年02月08日
    浏览(52)
  • 在Java中使用FileReader.read()进行读取文件时,为什么乱码?两个方法解决

     以上代码是有可能出现代码输出混乱的情况的,输出效果如下: 可能会出现乱码的问题: 原因可能是文件编码与程序读取时使用的编码不一致。在创建 FileReader 对象时,没有指定文件的编码格式,因此默认使用的是系统默认的编码格式。如果文件中包含非系统默认编码格式

    2024年02月03日
    浏览(44)
  • 【Linux操作系统】编译过程中遇到的问题-为什么加-c?执行文件提示无法执行二进制文件?main函数参数argc和*argv[]的作用和理解?

    在使用GCC编译器进行程序开发时,我们经常会遇到一些编译过程中的问题, 比如为什么要加上\\\"-c\\\"选项,以及为什么生成的可执行文件无法执行等问题。 本篇博客将详细介绍这些问题,并给出相应的代码和解释,帮助读者更好地理解GCC编译过程中的\\\"-c\\\"选项和main函数的参数a

    2024年02月12日
    浏览(63)
  • Oracle21C:Windows版本的安装、卸载、环境变量配置、避坑指南|ORA-12514|为什么安装目录没有bin目录

    安装Oracle21C(点击下载),因不得其法,各种报错,导致不能正常使用Oracle。  提示:版本是Oracle21C, 其他版本可能存在差异, 目前官网已更新到Oracle23C (进官网后,向下滚动,可下载其他版本)。  1)Oracle下载地址:官网下载页面 2)navecat下载地址:navecate 3)sqlplus下载地

    2024年01月25日
    浏览(53)
  • 【C语言】scanf和strcpy这类关键字和函数为什么不安全,使用VS编译会报错

    首先先说解决方法: 在程序最顶端加入这个代码段 这主要是微软的 C 运行时库实现将这些函数标记为不安全,主要原因是这些函数缺乏对输入长度的边界检查,容易导致缓冲区溢出漏洞。 会产生这样的报错: 即: C4996    \\\'strcpy\\\': This function or variable may be unsafe. Consider usin

    2024年02月14日
    浏览(57)
  • Isito 入门:为什么学 Istio、Istio 是什么

    本教程已加入 Istio 系列:https://istio.whuanle.cn 目录 1,Istio 概述 🚩聊聊微服务设计 🥇只使用 Kubernetes 部署容器, 🥈开始使用一些中间件,完善基础设施 ❓我为什么要学 Istio 💡所以,Istio 是什么 Istio 三个主要功能 Istio 原理 似乎用上 Kubernetes ,就是微服务系统了。 碰到很

    2024年02月06日
    浏览(34)
  • 什么是分布式操作系统?我们为什么需要分布式操作系统?

    分布式操作系统是一种特殊的操作系统,本质上属于多机操作系统,是传统单机操作系统的发展和延伸。它是将一个计算机系统划分为多个独立的计算单元(或者也可称为节点),这些节点被部署到每台计算机上,然后被网络连接起来,并保持着持续的通信状态。在分布式操作

    2024年02月16日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包