文件内容函数详解

目录

一、什么是文件?

二、文件的打开和关闭

1.文件指针是什么?

2.FILE是什么?

3.打开和关闭文件的指针变量

3.1 fopen

3.1.1文件的路径

绝对路径

相对路径

3.1.2 mode的参数

3.2 fclose

3.3实例

 三、文件的顺序读写

 1.函数介绍

1.1 fgetc和fputc 

 fgetc 

 fputc

1.2 fgets和fputs

fgets

fputs

1.3 fscanf和fprintf 

 1.4 fread和fwrite

四、文件的随机读写 

1.fseek

2.ftell

3.rewind

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

六、文件读取结束的判定

ferror

feof


一、什么是文件?

使用文件可以将数据直接存储到磁盘上,做到了数据的持久化(如微信聊天记录,购物记录等)

二、文件的打开和关闭

1.文件指针是什么?

在文件缓冲系统中,通常使用“文件类型指针”,简称为“文件指针

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息,这些信息是保存在一个结构体变量中的,该结构体类型是由系统声明的,取名FILE

2.FILE是什么?

在C语言中,FILE是一个结构体类型,用来表示文件流。它是在标准库中定义的,当使用文件指针时需要使用FILE类型的指针来指向文件流(抽象的概念,从文件中读取或写入数据的过程)

例如,VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

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* fp;//fp是文件指针变量

定义fp是一个指向FILE类型数据的指针变量,可以使fp(是一个结构体变量)指向某个文件的文件信息区,通过文件信息区可以访问文件。也就是说,我们可以通过fp(文件指针变量)来找到它所指向的文件

3.打开和关闭文件的指针变量

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

我们可以通过 FILE* 建立一个指针变量 指向 我们需要打开的文件

在ANSIC 规定使用 fopen函数来打开文件,fclose来关闭文件,这两个函数都是C语言标准库中的I/O函数

3.1 fopen

FILE *fopen(const char *filename, const char *mode);//打开文件

fopen 函数用于打开一个指定的文件,并返回一个指向该文件的文件流指针

其中,filename是要打开的文件的名称,mode是指定文件打开模式的字符串

3.1.1文件的路径

文件的名称分为 绝对路径 和 相对路径 

绝对路径

绝对路径是指从文件系统的根目录开始,一直到目标文件的完整路径

例如,在 Windows 系统中,绝对路径是这样:C:\Users\Username\Documents\file.txt

// 使用绝对路径打开文件
fp = fopen("C:\\Users\\Username\\Documents\\file.txt", "r");
相对路径

相对路径是指相对于当前源文件所在目录的路径,从当前目录开始。

例如,源文件位于C:\Users\Username\Documents目录中,打开该目录下的test.txt文件,可以使用相对路径test.txt来打开

//使用相对路径打开文件
FILE *fp = fopen("test.txt", "r");

打开上一级目录中的文件时,应用相对路径来打开

../test.txt 来打开 Username,这里的 .. 表示上一级目录

//打开上一级目录中的文件
FILE *fp = fopen("../test.txt", "r");

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

   

3.2 fclose

fclose函数用于关闭由fopen函数打开的文件

如果关闭成功了,该函数会返回0。如果关闭失败了,该函数会返回EOF(-1),即非零值

int fclose(FILE *stream);

stream是要关闭的已经打开的文件的指针

3.3实例

#include <stdio.h>
int main ()
{
   FILE * pFile;
   //打开文件
   pFile = fopen ("myfile.txt","w");

   if (pFile == NULL)
   {
      perror("fopen");
      return 1;
   }
   //关闭文件
   fclose (pFile);
   //把指针释放为NULL
   pFile=NULL;
   return 0;
}

在使用fclose函数关闭文件后,不需要将指针fp设置为NULL

但是,将指针设置为NULL是一个好习惯,它可以防止意外地再次使用已经关闭的文件指针

 三、文件的顺序读写

 

 1.函数介绍

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

1.1 fgetc和fputc 

 fgetc 
int fgetc ( FILE * stream );

从指定的流 stream(指针) 获取下一个字符(一个无符号字符),并把位置标识符往前移动

该函数以无符号 char 强制转换为 int 的形式返回读取的字符

如果调用时流位于文件末尾,则该函数返回 EOF 并为流设置 (feof) 的文件结束指示器

如果发生读取错误,该函数将返回 EOF 并为流设置错误指示器 (ferror

代码如下

#include <stdio.h>
int main ()
{
   FILE * pFile;
   //打开文件
   pFile = fopen ("myfile.txt","r");

   if (pFile == NULL)
   {
      perror("fopen");
      return 1;
   }
   
   //读文件,一次读一个字符
   in ch1=fgetc(pFile);//从文件内读
   in ch2=fgetc(stdin);//从键盘上读

   //关闭文件
   fclose (pFile);
   //把指针释放为NULL
   pFile=NULL;
   return 0;
}

 fgetc接收的参数不同,则读取的地方不同

 fputc
int fputc ( int char, FILE * stream );

char指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动

要编写的字符的 int 提升,写入时,该值在内部转换为无符号字符

如果没有发生错误,则返回所写的字符;如果发生错误,则返回 EOF 并设置错误指示器ferror

代码如下

#include <stdio.h>
int main ()
{
   FILE * pFile;
   //打开文件
   pFile = fopen ("myfile.txt","w");

   if (pFile == NULL)
   {
      perror("fopen");
      return 1;
   }
   

   //在pFile指向的文件内储存
   fputc('a', pFile);


   //打印到屏幕
   fputc('b',stdout);//标准输出流
   fputc('c',stderr);//标准错误流,同样可以输出到屏幕


   //关闭文件
   fclose (pFile);
   //把指针释放为NULL
   pFile=NULL;
   return 0;
}

1.2 fgets和fputs

fgets
char * fgets ( char * str, int num, FILE * stream );

str——指向一个字符数组的指针,该数组存储了要读取的字符串

num——要读取的最大字符数(包括最后的空字符),通常是使用以 str 传递的数组长度

stream——指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流(stdin 可以用作从标准输入读取的参数)

返回值——如果成功,函数返回str;  如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针;  如果发生读取错误,则设置错误指示器ferror),并返回空指针(但str指向的内容可能已更改)

代码如下

从文件中获取

#include <stdio.h>

int main()
{
   FILE * pFile;
   char mystring [10];
   pFile = fopen ("myfile.txt" , "r");

   if (pFile == NULL) 
   { 
     perror ("fopen");
     return 1;
   }
   else
   {
     if ( fgets (mystring , 10 , pFile) != NULL )
     {
        puts (mystring);
     }
     fclose (pFile);
     pFile=NULL;
   }
   return 0;
}

从键盘上获取

 我们从键盘上输入后,获取10个字符,但最后只打印了9个,是因为fgets函数会在最后自动添加一个空字符 '\0'(这样可以避免出现错误),所以调用fgets时,最多获取 n-1 个字符

fputs
int fputs ( const char * str, FILE * stream );

把字符串写入到指定的流 stream 中,但不包括空字符

注意:fput与 put 的不同之处不仅在于可以指定目标,而且 fput 不会写入其他字符,而 put 会自动在末尾附加换行符 

str——这是一个数组,包含了要写入的以空字符终止的字符序列

stream——这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流

返回值——成功时,将返回非负值。出错时,该函数返回 EOF 并设置错误指示器ferror

 代码如下

#include <stdio.h>

int main ()
{
   FILE *fp;
   fp = fopen("file.txt", "w+");
   if(fp==NULL)
   {
      perror("fopen"):
      return 1;
   }
   
   fputs("这是 C 语言。", fp);
   fputs("这是一种系统程序设计语言。", fp);

   fclose(fp);
   fp=NULL;
   return(0);
}

文件内容如下 (没有自动换行)

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

1.3 fscanf和fprintf 

//fscanf
int fscanf ( FILE * stream, const char * format, ... );
//scanf
int scanf ( const char * format, ... );
//sscanf
int sscanf ( const char * s, const char * format, ...);


//fprintf
int fprintf ( FILE * stream, const char * format, ... );
//printf
int printf ( const char * format, ... );
//sprint
int sprintf ( char * str, const char * format, ... );

比较 scanf 函数后,区别在于读取数据的来源不同

比较 printf 函数后,区别在于输出目标不同 

fscanf从指定的文件流中读取数据
scanf从标准输入流stdin中读取数据
sscanf从一个一空字符('\0')结尾的字符数组中读取数据
fprintf将格式化字符串输出到指定的文件流中
printf将格式化字符串输出到标准输出设备(通常是屏幕)
sprintf将格式化字符串输出到一个字符数组中(不是流)

 1.4 fread和fwrite

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

//fwrite
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

注意:fread和fwrite是用于读取和写入二进制数据,使用时fopen参数应用 "rb"/"wb"

 ptr 是指向存储 读取/写入 数据的缓冲区的指针(地址),size 是每个数据元素的大小(以字节为单位),count 是要读取的数据元素的个数,stream 是指向文件流的指针

函数返回实际 读取/写入 到的数据元素的个数

所创建的文件不可直接访问,用法相似,不再过多赘述

四、文件的随机读写 

1.fseek

//根据文件指针的位置和偏移量来定位文件指针
int fseek ( FILE * stream, long int offset, int origin );

stream——根据文件指针的位置和偏移量来定位文件指针

offset——这是相对 origin 的偏移量,以字节为单位,可以为负数

origin——用作偏移参考的位置。它由 <cstdio> 中定义的以下常量之一指定,专门用作此函数的参数:

常量参考位置
SEEK_SET文件的开头
SEEK_CUR文件指针的当前位置
SEEK_END文件的末尾 *

* 允许库实现不有意义地支持 SEEK_END(因此,使用它的代码没有真正的标准可移植性) 

返回值——如果成功,该函数将返回零。否则,它将返回非零值。如果发生读取或写入错误,则设置错误指示器ferror

代码如下

#include <stdio.h>

int main()
{
	FILE* pFile;
	pFile = fopen("example.txt", "wb");
	if (pFile == NULL)
	{
		perror("fopen");
		return 1;
	}
    
    //写入文本
	fputs("Hello World.", pFile);
	//修改指针位置
    //SEEK_SET即从文件开头的位置
    fseek(pFile, 5, SEEK_SET);
	//修改文本信息
    fputs("****", pFile);

	fclose(pFile);
	pFile = NULL;
	return 0;
}

当我们把 fseek(pFile, 5, SEEK_SET); 这行代码注释掉,文件内文本为 Hello World.****

我们放开后,文件内文本为 Hello****ld.

2.ftell

long int ftell ( FILE * stream );

 返回文件指针相对于起始位置的偏移量(当我们不知道指针的位置时,可以调用ftell来查看)

#include <stdio.h>

int main()
{
	FILE* pFile;
	pFile = fopen("example.txt", "rb");
	if (pFile == NULL)
	{
		perror("fopen");
		return 1;
	}

    //我们在文件内放入 abcdefgh
	fputs("abcdefgh", pFile);

	int ch=fgetc(pFile);//用int接收,fgetc返回值类型为int
    printf("%c\n",ch);//打印返回的字符

    ch = fgetc(pFile);
    printf("%c\n",ch);
    
	int pos = ftell(pFile);
	printf("%d\n", pos);
	
	fclose(pFile);
	pFile = NULL;
	return 0;
}

此时偏移了两个字符,pos的结果应该为2

a
b
2

3.rewind

void rewind ( FILE * stream );

让文件指针的位置回到文件的起始位置(也可以用fseek来实现,fseek(pFile,0,FEEK_SET)

我们还用刚才的代码来示例 

#include <stdio.h>

int main()
{
	FILE* pFile;
	pFile = fopen("example.txt", "rb");
	if (pFile == NULL)
	{
		perror("fopen");
		return 1;
	}

    //我们在文件内放入 abcdefgh
	fputs("abcdefgh", pFile);

	int ch=fgetc(pFile);//用int接收,fgetc返回值类型为int
    printf("%c\n",ch);//打印返回的字符

    ch = fgetc(pFile);
    printf("%c\n",ch);
    
    rewind(pFile);//指针返回起始位置
    
	int pos = ftell(pFile);
	printf("%d\n", pos);
	
	fclose(pFile);
	pFile = NULL;
	return 0;
}

当fgetc偏移两个字符后,rewind又让指针回到了起始位置,此时pos的值为0

a
b
0

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

在介绍文件时,我们提到了数据文件,而数据文件,又可以分文文本文件和二进制文件 

 六、文件读取结束的判定

 feof 和 ferror 都是用来检查文件流状态的函数,但它们检查的状态不同

 ferror

 ferror是用来检查文件流是否发生错误,发生错误返回非零值,否则返回零

int ferror ( FILE * stream );

 如我们上面介绍的函数中,返回值错误时会设置feeor

#include <stdio.h>
int main ()
{
  FILE * pFile;
  pFile=fopen("myfile.txt","r");
  if (pFile==NULL)
  {  perror ("Error opening file");
     return 1;
  }
  else 
  {
    fputc ('x',pFile);
    if (ferror (pFile))
    {
       printf ("Error Writing to myfile.txt\n");
       break;
    }
    fclose (pFile);
  }
  return 0;
}

在这个例子中,我们用ferror来判断函数读取字符后是否发生错误,如果返回值为非零(即发生错误),则进入if循环内并结束循环

feof

feof是用来检查文件流是否到达了文件末尾,返回非零值;否则返回零

int feof ( FILE * stream );

 如我们上面介绍的 fgetc 函数,如果读取时到达了文件末尾,则返回feof

#include <stdio.h>

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

    fp = fopen("file.txt", "r");
    if (fp == NULL)
    {
        perror("fopen");
        return 1;
    }

    while (!feof(fp))
    {
        ch = fgetc(fp);
        if (ch != EOF) 
        {
            putchar(ch);
        }
    }

    fclose(fp);
    return 0;
}

在这个例子中,我们用feof来检查是否到达了文件末尾,如果返回值为非零(即发生错误),则不进入while循环内

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天王级选手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值