C语言由浅入深讲解文件的操作下篇

 更新时间:2022年04月01日 12:08:36   作者:_奇奇  
C语言具有操作文件的能力,比如打开文件、读取和追加数据、插入和删除数据、关闭文件、删除文件等。与其他编程语言相比,C语言文件操作的接口相当简单和易学

第一篇讲了文件的基本概念,和文件如何打开和关闭。第二篇主要介绍文件的顺序读写和随机读写。外加文件缓冲区的知识点。

文件的顺序读写

字符输入输出fgetc和fputc

fgetc

fgetc:字符输入函数,也就是读文件时用的函数。

函数功能:Read a character from a stream

从一个文件中读一个字符到内存中。

函数原型:

int fgetc( FILE *stream );

参数为stream,也就是文件指针。

返回值:fgetc return the character read as an int or return EOF to indicate an error or end of file.该函数调用成功会返回读取到的的字符的ASCIIC码值;若读取文件时发生错误,或是已经读取到文件末尾,则返回EOF。

举例:将data.txt文件中的内容读取,并打印。

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;//文件打开失败,失败返回
	}
	//对文件进行输入字符操作
	int ch = 0;
	while ((ch = fgetc(pf))!= EOF)
	{
		printf("%c", ch);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

fputc:

函数功能:从内存中写一个字符到文件中。也就是输出字符。

函数原型:

int fputc( int c, FILE *stream );

第一个参数为待输出的字符,第二个参数是文件指针。

返回值:Each of these functions returns the character written. For fputc , a return value of EOF indicates an error.

如果正常运行则返回此字符,如果返回EOF则意味着失败。

举例:将字母a~z写入到data.txt文件中

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "w");
	//文件打开失败,失败返回
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	//对文件进行输出字符的操作
	char i = 0;
	for (i = 'a'; i <= 'z'; i++)
	{
		fputc(i, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

文本行输入输出函数fgets和fputs

fgets和fputs是对文本行的操作,相当于对字符串的操作。这是不同于fgetc和fputc的地方。

fgets:

函数功能:从文件中读一行字符到内存中,也就是输入。

函数原型:

char *fgets( char *string, int n, FILE *stream );

第一个参数是指向文件字符串的指针,第二个参数是读几个字符的意思,第三个参数是指向文件的指针。

返回值:Each of these functions returns string. NULL is returned to indicate an error or an end-of-file condition. Use feof or ferror to determine whether an error occurred.每一个这样的函数结束后正常情况返回一个指向这个字符串的字符指针。如果返回NULL则意味着遇到错误,或者是文件结束。但是重点来了~,想要判断到底是错误导致的返回,还是文件结束导致的返回,还需要使用feof函数和ferror函数来判断。

下面有涉及feof函数的用法

举个例子。

   //feof是用来在结束后判断是什么原因结束的
    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);
}

注意:

1.在fgets函数读取到指定字符数之前,若读取到换行符(’\n’),则停止读取,读取带回的字符包含换行符。

2. fgets函数读取到第n-1个字符时都没有遇到换行符(’\n’)时,则返回读到的前n-1个字符,并在末尾加上一个NULL字符返回。这样加起来共n个字符

fputs:

函数功能:写一行字符串到文件中,也就是输出。

函数原型:

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

第一个参数为指向内存中这个字符串的指针,第二个参数为指向这个文件的文件指针。返回值:该函数调用成功会返回一个非负值;若输出时发生错误,则返回EOF。

格式化输入输出函数fscanf和fprintf

fscanf和fprintf也叫格式化输入(读)和输出(写)函数。

fscanf:

函数功能:按照一定的格式如%s,%c,从指定文件的位置输入到内存中。

函数原型:

int fscanf( FILE *stream, const char *format [, argument ]... );

fscanf函数的第一个参数是读取数据的位置也就是文件指针,第二个参数也就是scanf函数的参数,也就是取地址。

除了第一个参数是需要指针位置其余和scanf函数操作一样。

fprintf:

函数功能:将内存中的数据以一定的格式输出到文件中。也就是打印,也称为写。

函数原型:

int fprintf( FILE *stream, const char *format [, argument ]...);

第一个参数是文件指针,第二个参数和printf函数一样,会用printf函数就会用这个函数。

举例:

include <stdio.h>
#include <string.h>
#include <errno.h>
struct S
{
	char name[20];
	char sex[5];
	int age;
};
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	//如果文件打开失败,失败返回
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	//对文件进行格式化输入输出操作
	struct S tmp = { 0 };
	fscanf(pf, "%s %s %d", tmp.name, tmp.sex, &(tmp.age));
	printf("%s %s %d\n", tmp.name, tmp.sex, tmp.age);
	//可以打印出来,我这里没打印。
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

二进制输入输出函数fread和fwrite

fread:

函数功能:Reads data from a stream.从一个流中读取数据到内存中。

函数原型:

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

第一个参数是buffer是内存的意思,第二个参数是要读的数据的类型,第三个参数是读取的个数,第四个参数是文件指针。总的意思是从文件指针指向的文件读取count个size大小的数据到内存buffer中。

返回值:若在读取过程中发生错误或是在未读取到指定元素个数时读取到文件末尾,则返回一个小于count的数。

fwrite:

函数功能:Writes data to a stream.写入二进制数据到文件中

函数原型:

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

第一个参数是输出数据的位置,第二个参数是要输出数据的元素个数,第三个参数是每个元素的大小,第四个参数是数据输出的目标位置。返回值:该函数调用完后,会返回实际写入目标位置的元素个数,当输出时发生错误或是待输出数据元素个数小于要求输出的元素个数时,会返回一个小于count的数。

举例:以wb输出到文件

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "wb");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	//对文件以二进制形式进行输出操作
	int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	fwrite(arr, sizeof(int), 10, pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

文件的随机读写

fseek

函数介绍:定位文件指针,以文件指针当前的位置,偏移到想定位的位置。向前偏移是负的,比如-1,-2,向后偏移是正的。

  • SEEK_CUR:从当前指针的位置偏移
  • SEEK_SET:从文件的起始位置开始偏移
  • SEEK_END:从文件的末尾开始偏移

函数原型:

int fseek( FILE *stream, long offset, int origin );

第一个参数是文件指针,第二个参数是要偏移的偏移量。第三个参数是从什么位置开始偏移。举例。

/* fseek example */
#include <stdio.h>
int main ()
{
  FILE * pFile;
  //打开文件
  pFile = fopen ( "example.txt" , "wb" );
  //以一行的形式写文件
  fputs ( "This is an apple." , pFile );
  //让文件指针从文件的起始位置开始偏移9个单位。
  fseek ( pFile , 9 , SEEK_SET );
  //继续写文件
  fputs ( " sam" , pFile );
  //关闭文件
  fclose ( pFile );
  return 0; 
  }

ftell

函数介绍:可以返回文件指针相对于起始位置的偏移量

函数原型:

long ftell( FILE *stream );

返回值类型为long int,第一个参数是文件指针。

fwind

函数介绍:让文件指针回到文件的起始位置。fseek函数也可以达到同样的效果。

函数原型:

void rewind( FILE *stream );

举例

/* rewind example */
#include <stdio.h>
int main ()
{
  int n;
  FILE * pFile;
  char buffer [27];
  //打开文件
  pFile = fopen ("myfile.txt","w+");
  for ( n='A' ; n<='Z' ; n++)
   {
   	 fputc ( n, pFile);
   }
  //使指针回到起始位置
  rewind (pFile);
  fread (buffer,1,26,pFile);
  fclose (pFile);
  buffer[26]='\0';
  puts (buffer);
    return 0;
   }

文本文件和二进制文件

数据文件:可以分为文本文件和二进制文件

二进制文件:文本文件可以肉眼看懂,二进制文件则是乱码看不懂。

数据在内存中是以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件文本文件:如果要求在外存中以ASCII码的形式存储,则需要在存储前转换。如果以ASCII字符的形式存储文件就叫做文本文件。

具体例子如下。

一个数据在内存中是怎么存储的呢?

如果整数10000以ASCII码的形式输出到磁盘,则占用5个字节。如果以二进制形式输出到磁盘则占用4个字节。

在这里插入图片描述

文件结束的判定

feof

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

函数功能:应用于当文件读取结束的时候,用ferror判断是读取失败结束,还是遇到文件末尾结束。

1.文本文件读取是否结束,判断返回值是否为EOF(fgetc),或者是否为NULL(fgets)等。每个函数有每个特定的结束标志。

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

正确使用例子

#include <stdio.h>
#include <stdlib.h>
int main(void) {
    int c;
     // 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    //如果为0,则打开失败
    if(!fp)
    {
        perror("File opening failed");
        return EXIT_FAILURE;
   }
 //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
   { 
       putchar(c);
   }
   //feof是用来在结束后判断是什么原因结束的
    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);
}

文件缓冲区

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

在这里插入图片描述

举例:C语言代码也就是用户程序,要在屏幕上打印信息。则需要调用printf函数,而printf函数则调用了系统的API,让操作系统在屏幕上打印信息。但操作系统要为好多程序服务。所以在操作系统解决前,先放到文件缓冲区,程序攒满了再交给操作系统解决。

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

到此这篇关于C语言由浅入深讲解文件的操作下篇的文章就介绍到这了,更多相关C语言 文件操作内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C/C++中退出线程的四种解决方法

    C/C++中退出线程的四种解决方法

    本篇文章是对C/C++中退出线程的四种解决方法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C++构造函数抛出异常需要注意的地方

    C++构造函数抛出异常需要注意的地方

    这篇文章主要介绍了C++构造函数抛出异常需要注意的地方,帮助大家更好的理解和学习c++,感兴趣的朋友可以了解下
    2020-08-08
  • C++实现LeetCode(98.验证二叉搜索树)

    C++实现LeetCode(98.验证二叉搜索树)

    这篇文章主要介绍了C++实现LeetCode(98.验证二叉搜索树),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C语言的程序环境与预处理你真的了解吗

    C语言的程序环境与预处理你真的了解吗

    这篇文章主要为大家详细介绍了C语言的程序环境与预处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • C++实现大数乘法算法代码

    C++实现大数乘法算法代码

    这篇文章主要介绍了C++实现大数乘法算法代码的相关资料,需要的朋友可以参考下
    2015-03-03
  • C++ 动态规划算法使用分析

    C++ 动态规划算法使用分析

    动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解
    2022-03-03
  • C++文件输入输出fstream使用方法

    C++文件输入输出fstream使用方法

    C++标准库提供了<fstream>头文件,其中包含了用于文件输入输出的相关类和函数,本文将详细介绍<fstream>头文件的使用方法,包括函数原型、打开文件、读取和写入文件、以及错误处理等注意事项,感兴趣的朋友跟随小编一起看看吧
    2023-10-10
  • C++动态加载so/dll库的实现

    C++动态加载so/dll库的实现

    本文主要介绍了C++动态加载so/dll库的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • C语言数据结构算法之实现快速傅立叶变换

    C语言数据结构算法之实现快速傅立叶变换

    这篇文章主要介绍了C语言数据结构算法之实现快速傅立叶变换的相关资料,需要的朋友可以参考下
    2017-06-06
  • C++简明讲解缺省参数与函数重载的用法

    C++简明讲解缺省参数与函数重载的用法

    所谓缺省参数,顾名思义,就是在声明函数的某个参数的时候为之指定一个默认值,在调用该函数的时候如果采用该默认值,你就无须指定该参数。C++ 允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载,借助重载,一个函数名可以有多种用途
    2022-06-06

最新评论