数据文件的使用(C语言笔记)

一、 输入输出的基本概念

在这里插入图片描述

数据在外部设备和内存之间的传递,我们称之为输入输出。

二、文件概念

在C语言中,“文件”的概念具有广泛的意义,它把和主机进行数据交换的输入输出设备都看作一个文件。即把实际的物理设备抽象为逻辑文件,它们也被称为设备文件
如:

  1. 键盘作为标准输入文件,文件名stdin
  2. 显示器作为标准输出设备,文件名stdout,标准错误输出文件stderr
  3. 打印机也可以作为输出文件,文件名PRN

注:数值12345在ASCII文件中和二进制文件中的存放形式不同,整数 12345
i. 若存于文本文件中,占 5 个字节。
即存放 5 个 ASCII 字符(看成字符串),
本质上存储的是二进制值。
ii. 若存于二进制文件中,占 4 个字节(即内存映象)。
因为一个整数在内存中占 4 个字节,
本质上存储的仍是二进制值。

三、 缓冲

引入缓冲的目的是解决CPU的运行速度和外部设备操作速度不匹配的矛盾。提高计算机系统运行速度。以输出操作为例,在内存中开辟一个输出缓冲区,程序中的每次输出,不是立刻直接驱动并输出到外部设备上的,而是首先输出到缓冲区中,当缓冲区被写满或缓冲区不满但程序干涉时,才将缓冲区中的数据成批送往外部设备,这样可以减少对外部设备的驱动次数,提高输出速度。
在这里插入图片描述

四、文件的读写过程

(一) 预备知识

  1. 无论是文本文件还是二进制文件,文件都可以看成数据流,数据流由若干字节构成,以文件结束符EOF结尾。
    在这里插入图片描述
  2. 在程序中要读写一个文件时,必须要通过指向文件的指针进行。
  3. 需知道待读写文件的文件名、文件类型、文件的操作方式(即读写方式)以及文件的读写位置指针等信息。
  4. 信息一般存放在一个文件信息区中,文件信息区的本质是一个结构体变量,其各个成员存放上述信息。
  5. 在缓冲文件系统中,对每个正在使用的文件,都要使用一个FILE类型的结构变量,该结构变量用于存放文件的有关信息,如:文件名、文件状态等。
  6. 在C语言中,无论是一般磁盘文件还是设备文件,都要通过文件结构的相应成员数据进行输入输出处理。
  7. 文件结构不需要用户定义,由系统事先定义好。
  8. 文件结构已由系统定义,在程序中若想读写一个文件,则首先必须为该文件建立一个信息区,用一个指针指向该信息区。
  9. 定义一个FILE类型(文件型)文件信息区指针(简称文件指针):
    FILE * 文件型指针变量名;
    例如: FILE *fp;
    fp是一个指针变量,指向文件结构。如要同时使用多个文件时,必须有多个不同的文件指针。程序运行过程中,文件指针是指定待读写文件的唯一标识。

(二) 读写过程

FILE *file;
file=fopen(" "," ");

(其中第一个双引号里是文件地址,文件地址必须用 \ \ 隔开,不然会出错,第二个是打开类型)

打开类型汇总:

r :以只读方式打开文件,该文件必须存在。
r+ :以可读写方式
打开文件,该文件必须存在。
w :打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
w+: 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
a :以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
a+: 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留)
wb :只写打开或新建一个二进制文件;只允许写数据
wb+ :读写打开或建立一个二进制文件,允许读和写。
ab+ :读写打开一个二进制文件,允许读或在文件末追加数据。
rb+ :读写打开一个二进制文件,允许读写数据,文件必须存在。
一张好图:
在这里插入图片描述

注意:
1.当程序开始运行时,系统自动打开三个标准文件:
标准输入(文件指针stdin )
标准输出(文件指针stdout )
标准出错输出(文件指针stderr )
2.如果程序从stdin输入数据,则从键盘输入数据。
3.如果程序向stdout写数据,则写到屏幕上。

(三) 文件的打开与关闭

1.打开文件

——建立“文件信息区”,返回一个文件指针。
即通过指针建立用户程序与文件的联系,为文件开辟缓冲区。
FILE *fp;
fp=fopen(文件名,文件的使用方式);
文件名——字符串,可带路径
文件的使用方式——字符串
例:

 fp = fopen("data.dat ","r");
 fp= fopen("d:\\c\\data.dat ","r");
      //以读方式打开正文文件 data.dat, 它事前应存在。若打开不成功,则 fopen( ) 函数返回空指针 NULL 。

一般以如下方式处理

#include <stdio.h>  
#include<stdlib.h>
int main()
{
	//一般如下处理
	FILE*fp;
	fp=fopen("d:\\data.dat","r");//以只读方式打开数据文件
	if (fp==NULL)
	{
		printf("打不开");
		exit(1);//exit是系统函数,表示终止程序的运行
	}}
2.关闭文件

对文件读写完毕,要关闭该文件,释放信息区。
调用格式 fclose(fp); /* fp是文件指针 */
即切断文件和程序的联系,将文件缓冲区的内容写入磁盘,并释放文件指针。

注意:若文件关闭成功,则 fclose( ) 函数返回返回值为 0 。
若文件关闭失败,则返回非0值。

综上标准操作如下:

#include <stdio.h>
#include<errno.h>
#include<string.h>
int main()
{
    FILE*p=fopen("Contact.txt","r"); //打开文件输入文件地址,和打开方式
    if(p==NULL) //如果传入空指针则会报错
    {
        printf("%s", strerror(errno));//printf("%s", strerror(errno)) 用于输出当前的错误描述。
        //errno 是一个全局变量,它保存了最近一次发生的错误代码。strerror(errno) 将根据这个错误代码返回相应的错误描述字符串。
    }
    fclose(p); //关闭文件
    p=NULL;  //防止变为野指针
    return 0;
}

五、 文件的读写

1. 文件顺序操作

对文件的操作(文件读写)必须按文件中字符的先后顺序进行,只能在操作了第i个字符后,才能操作第i+1个字符。
在对文件操作时,文件的位置指针由系统自动向后(文件尾方向)移动。

2. 文件读写函数

  1. 读写一个字符:fgetc函数和fputc函数。

  2. 读写一行字符串:fgets函数和fputs函数。

  3. 格式化读写:fscanf函数和fprintf函数。

  4. “块”读写:fread函数和fwrite函数。

  5. “字”(整数)读写:getw函数和putw函数。

  6. ungetc函数用于退回一个字符到输入缓冲区中。

  7. feof函数用于在文件的读写过程中,检测是否到达文件结束

文件I/O 函数标准终端I/O函数作用
fgetcgetchar输入一个字符
fputcputchar输出一个字符
fgetsgets输入一行字符串
fputsputs输出一行字符串
fscanfscanf格式化输入函数
fprintfprintf格式化输出函数
(一) fgetc函数和fputc函数

用于读写一个字符,它们的函数原型是:

int fgetc(FILE *fp) ;      
             /* 功能:从fp指定的文件中读入一个字符 */
int fputc(int c, FILE *fp) ;  
             /* 功能:将字符c写入fp指定的文件中 */
(二)fgets函数和fputs函数

·fgets 原型为:

char * fgets(char *s, int n, FILE *fp) ; 
          /* 功能:从fp 指定的文件中读入一行字符串,

最多读取n-1个字符,并把它们存放到字符数组s中,若在读入n-1个字符之前遇到换行符 ‘\n’ 或文件结束符EOF,则结束读入。

·fputs 原型为:

int fputs(const char *s, FILE *fp) ;   
      /* 功能:将字符串s 写到fp指定的文件中  */

注意:
~fgets与gets的区别:

fgets将’\n’作为字符读入到字符串中,
而gets不把’\n’读入到字符串中。

~fputs与puts的区别:

fputs原样输出字符串,不增加输出’\n’;
而puts将字符串输出后,增加输出’\n’。

(三) fscanf函数和fprintf函数

fscanf 函数用于文件格式化的输入,原型为:

int fscanf(FILE *fp, const char *format, 输入量地址列表) ; 

fprintf函数用于文件格式化输出,原型为:

int fprintf(FILE *fp, const char *format, 输出量列表) ; 

参数fp 是文件指针,参数format是格式控制字符串。
与标准格式化输入输出函数scanfprintf的原型比较,多了第一个参数——文件指针,用于指定输入输出的数据文件。
其他的使用方式和 scanfprintf 没有区别。

scanf(%d”,&x) 等价于 fscanf(stdin,%d”, &x)
(四) feof函数

函数原型:

int feof(FILE *fp) ;
           /* 功能:判断fp指定的文件是否到达了文件结尾处  */
           /* 如果到达,则函数返回 “真”;否则返回“假” */

feof函数常用于循环读取文件内容的场景中,通过检查文件流的结束标志来确定是否已到达文件末尾。
例:以下是一个使用feof函数的示例代码,用于逐行读取文件内容并输出到控制台

#include <stdio.h>

int main() {
    FILE *fp;
    char line[100];

    fp = fopen("file.txt", "r");
    if (fp == NULL) {
        printf("无法打开文件\n");
        return 1;
    }

    while (!feof(fp)) {
        if (fgets(line, sizeof(line), fp) != NULL) {
            printf("%s", line);
        }
    }

    fclose(fp);
    return 0;
}
(五)ungetc函数的使用

函数原型如下:

int ungetc(int c, FILE *fp) ; 

功能:将c字符退回到fp指定的输入数据流中。
:假定文本文件data.txt的内容是字符流"ABCDEFG…",下面的函数读入其前三个字符,按逆序退回这三个字符,然后再读入前三个字符。通过本例,读者可以学习ungetc函数的使用,同时能够体会到文件缓冲区的意义。

int main( )
{	
    FILE *fp;
    char ch1, ch2, ch3; 
    if((fp = fopen("data.txt", "r"))==NULL)
    { 	printf("Can not open data.txt!\n");
 	exit(1);   
    } 
    ch1=fgetc(fp);     	ch2=fgetc(fp);     ch3=fgetc(fp);
    printf("%c%c%c,", ch1, ch2, ch3);
    ungetc(ch1,fp);    ungetc(ch2,fp);    ungetc(ch3,fp);
    ch1=ch2=ch3='X';
    ch1=fgetc(fp);     	ch2=fgetc(fp);    ch3=fgetc(fp);
    printf("%c%c%c\n", ch1, ch2, ch3);
    fclose(fp);
    return 0;
}

例1

从键盘输入以回车结尾的一行字符,将其写入文本文件:

# include <stdio.h>     /* 文件操作必须包含此头文件 */
# include <stdlib.h> 
int main( )
{	FILE *fp; 
	char filename[30], ch;       /* filename存放文件名  */
	printf("Please enter the file name: ");
	gets(filename);      /* 用标准输入函数输入目标文本文件名 */
	fp = fopen(filename, "w");   
	if(fp==NULL)
	{ 	printf("Can not open file %s!\n", filename);
		exit(1);  
	} 
	while((ch=getchar( ))!='\n')       /*  A  */
		fputc(ch, fp);                   /*  B  */
	fclose(fp);
	return 0;
}

例2

文本文件的复制
以下程序用于将一个源文件的内容复制到一个目标文件。

#include <stdio.h> 
#include <stdlib.h>
int main( )
{
	FILE *fp1, *fp2;
	char infile[30], outfile[30], ch;  
                      /* infile存放源文件名,outfile 存放目标文件 */
	printf("Please enter an input file name: ");
	gets(infile);        /* 用标准输入函数输入源文件名 */
	fp1 = fopen(infile, "r");   
	if(fp1==NULL)
	{ 
		printf("Can not open file %s!\n", infile);
		exit(1);   
	} 

	printf("Please enter an output file name: ");
	gets(outfile); /* 用标准输入函数输入目标文件名 */
  	fp2 = fopen(outfile, "w");
	if(fp2==NULL)
	{ 
		printf("Can not open file %s!\n", outfile);
		exit(2);  
	}
	while((ch=fgetc(fp1))!=EOF) 
		fputc(ch, fp2);       
	fclose(fp1);
	fclose(fp2);
	return 0;
}

例3

从正文文件in.txt中读入数据到二维数组中,调用函数分别求该二维数组的主、辅对角线上的元素之和,然后将二维数组的数据以矩阵方式写入另一正文文件out.txt,最后写入求和结果。

int main( )
{
	void sum(int a[4][4], int *, int *); /* 函数原型说明 */
	FILE *fp1, *fp2;
	int a[4][4], i, j, sum1, sum2;
	if((fp1=fopen("dada.in", "r"))==NULL)
                                                       /* 打开输入数据文件 */
	{ 
		printf("Can'nt open dada.in!\n");
		exit(1);   
	}
	if((fp2=fopen("data.out", "w"))==NULL)
                                                      /* 打开输出数据文件 */
	{
		printf("Can'nt open data.out!\n");
		exit(2);  
	}
for(i=0; i<4; i++)
		for(j=0; j<4; j++)
			fscanf(fp1, "%d", &a[i][j]); /* 从文件读元素值 */
	sum(a, &sum1, &sum2); /* 调用函数计算对角线元素之和 */
	for(i=0; i<4; i++)
    {
		for(j=0; j<4; j++)
			fprintf(fp2, "%4d", a[i][j]); /* 写数组元素到文件 */
		fprintf(fp2, "\n");
    }
	fprintf(fp2, " sum1=%d\n sum2=%d\n", sum1, sum2); /* 写求和结果到文件 */ 
	fclose(fp1);
	fclose(fp2);
	return 0;
}
void sum(int a[4][4], int *sum1, int *sum2)
                      /* 通过指针带回多个计算结果 */
{
	int i;
	*sum1=*sum2=0;
	for(i=0; i<4; i++)
	{
		*sum1 = *sum1 + a[i][i];
		*sum2 = *sum2 + a[i][3-i];
	}
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值