20201022-成信大-C语言程序设计-补充内容-文件

文件

用文件的方式,将数据长期保存

文件有格式

文件有规范

C下面的文件就是一个结构,用指针来操作

对CPU而言,就是一种设备【用于读写】

  • 在CPU控制下,由内存写到文件
  • 在CPU控制下,由文件读到内存

文件必须按原产生的类型标准来操作读写,否则,就会“乱码”

1C语言中的文件

  • 程序文件
    • 源文件
    • 目标文件
    • 可执行文件
  • 数据文件
    • 文本文件,ASCII字符形式,可以对字节里的二进制进行编码,方便人的理解
    • 二进制文件,机器直接用的文件

2文件缓冲区

  • ANSIC 标准采用“缓冲文件系统”处理的数据文件的
    • 所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在 使用的文件开辟一块“文件缓冲区”。
      • 从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘 上。
        • CPU处理和IO读写之间,有速度差异,不然,CPU就会等待【浪费】
        • 从CPU到文件的两个方向:CPU读,CPU写
        • 文件,本质上是磁盘上的数据,即外围设备中的数据
        • 缓冲区思想 == 缓冲带 == 缓冲池
        • 类似的应用:打印机缓冲,
        • 目的:利用中间地带,缓解速度矛盾,提高资源利用率
      • 如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐 个地将数据送到程序数据区(程序变量等)。
      • 缓冲区的大小根据C编译系统决定的(看不懂再看下面)
        • 这就相当于你嗑瓜子,垃圾桶离你很远【必须的,如办公室里不能放这个桶,你又在办公室里】的时候,你难道要吃一个跑过去扔一个吗?那么我们就是嗑一把瓜子后,把瓜子皮一次送往垃圾桶,而文件缓冲区就相当于你聚瓜子皮的地方;
        • 【某个位置】,即聚皮的地方,即缓冲区
        • CPU写数据时,把数据先组织好,放在内存【某个位置】中,等到满时或是完时,内存一次写到硬盘中。
        • CPU读数据时,把数据从磁盘读入,先组织好存放在内存【某个位置】中,等到满时或是完时,CPU一次读入

3基本过程

3.1常见操作

  • 打开 fopen
    • 成功:返回文件指针,即文件
    • 不成功:返回空指针,即NULL
  • 操作 write/read
    • fscanf(fp,格式列表,内存地址列表);
      • 成功:返回读出的数据个数
      • 不成功:返回EOF
    • fprintf(fp,格式列表,输出数据列表);
      • 成功:返回写到文件的字符个数
      • 不成功:返回一个负数
  • 关闭 fclose
    • 成功:返回0
    • 不成功:返回EOF
// 0 文件指针准备
FILE* fp;
// 1 打开文件
FILE * fopen ( const char * filename, const char * mode ); 
FILE* fp=fopen("e:/text.txt","r");
// 2 处理
// n 关闭文件
int fclose ( FILE * stream );
fclose(fp);

3.2对fopen的补充说明

1.如果文件打开成功,fopen()函数将返回给文件的文件指针,以后就可以通过该文件指针来对文件进行各种操作,而不用再使用文件名。

2.如果文件打开失败,fopen()函数返回空指针NULL.

3.可以通过判断fopen()函数的返回值来确定文件是否正常打开

if(fp=fopen("filename","r")==NULL)
{
    
    
    printf("Can not open this file!\n");
    exit(0)}

3.3文件的关闭

  • 使用完文件后应及时地对文件进行关闭,及时关闭文件的理由至少有以下两点:
    • 使用缓冲文件系统时,如果数据缓冲区未满而又不关闭文件就退出程序的运行,则会造成数据缓冲区内的数据丢失。
    • 一个系统内能够同时打开的文件有一定的数量限制。如果不及时地关闭已经不使用的文件,就可能造成打开其他文件时出错。
函数原型:int fclose( FILE *stream );  
调用形式:fclose(文件指针);  
函数功能:将与指定文件指针相关联的文件关闭。   
    fclose函数正常关闭了文件,返回0,否则返回EOF(-1)。
建议:在fclose操作完成后,可以再做一下fp=NULL;的操作    

说明:

1.该函数用于关闭使用fopen()函数打开的文件,一般程序在这之前打开了几个文件,就必须调用fclose()关闭几个文件。

2.标准设备文件stdin、stdout和stderr由系统自动打开,系统会自动关闭

3.函数正常关闭文件后返回值为0,出错则返回符号常量EOF(值为-1)

4.若文件关闭后又想再次对这个文件进行操作,需要再一次使用fopen()函数打开文件。

3.4文件尾检测

  • 程序中需要判断文件是否处理完成,即文件内部记录指针是否已移动到了文件尾标志处。
  • EOF(仅用于文本文件)
    • 由于文本文件中任何字符的编码均不是-1,可以用-1表示文本文件的文件尾标志,系统中用符号常量EOF来表示。在输入流中表示为ctrl+z。
  • feof(pf)
    • ANSI C提供了一个测试文件状态的函数feof(pf),当文件未结束时feof函数的值为0,否则为非0值。
    • 使用函数feof来判断文件是否结束既可用于文本文件,还可用于二进制文件。
    • 这个方法,会多读一次文件。

4对单个文件的操作方法

在这里插入图片描述

4.1单字符输入函数fgetc

  • 函数原型:int fgetc(FILE *stream );
  • 函数调用:ch=fgetc(fpt); //注意,ftp和ch分别为已经定义的文件指针变量和字符变量
  • 函数功能:从指针变量fpt相关联的文件中读取一个字符并将其赋给字符型变量ch;执行函数时遇文件结束符或在执行中出错时返回值为EOF(-1)。

示例:

  • 功能:从键盘输入一个文本文件的名称,并将其内容显示在屏幕上。

  • 解释:

    • 1.文件名一般啊包含为多个字符的字符串,可以定义一个字符数组filename进行存放。
    • 2.要从文件中读取内容,fopen()函数的打开方式可设置为“r".
    • 3.文件打开后可以使用fgetc()函数一个一个的读取字符,然后使用putchar将读到的字符显示到屏幕上,知道文件读完为止。
    • 4.由于fgetc()函数遇到文件尾时返回EOF,因此可构建一个while循环判断文件是否读完。

程序代码如下:

#include <stdio.h>
#include <stdlib.h>
void  main()
{
    
    
	FILE *fp;
	char ch, filename[50];
	printf("请输入文件名:");
	gets(filename);
	if ((fp=fopen(filename, "r")) == NULL)  //打开文件
	{
    
    	
		printf("打开文件失败!\n");
		exit(0);
	}
	while ((ch = fgetc(fp)) != EOF)  //检测文件读取是否达到尾部
    {
    
    
        putchar(ch);   //输出到屏幕上
    }
		
	fclose(fp);   //关闭文件
	system("pause");
}

字符读取函数fgetc()可从文件数据流中一次读取一个字符,然后读取光标移动到下一个字符,并逐步将文件的内容读出。如果字符读取成功,则返回所读取的字符,否则返回EOF(end of file)。EOF是表示数据结尾的常量,真值为-1。另外,要判断文件是否读取完毕,可利用feof()进行检查。未完返回0,已完返回非零值。

5操作实例

P320

/* 
    读文件,完成运算
编写一程序P320.C实现以下功能
  在文本文件Comp.txt里有需要计算结果的整数算式,每个算式占一行且文件中只有一个算式,运算类型只有“加法(+)”或者“减法(-)”且运算符前后至少有一个空格。
计算该算式的结果并在屏幕上显示。
  单击此处下载程序运行时测试用的算式文件Comp.txt(加法示例,编程时还应考虑算式为减法的情况)并保存到程序P320.C所在的文件夹且文件名保持不变。
编程可用素材:
printf("%d + %d = %d\n");
printf("%d - %d = %d\n");
  程序的运行效果应类似地如图1和图2所示。

123 + 556 = 679
图1 程序运行效果示例(测试用算式文件Comp.txt内容为整数加法算式)

123 - 556 = -433    
 */
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    
    
    int data1, data2;
    int result;
    char ch;    
    FILE *fp;

    // open file
    if ((fp = fopen("Comp.txt", "r")) == NULL)
    {
    
    
        printf("Open file failure.\n");
        exit(0);
    }
    // read data
    // 只有一行数据,直接格式化读取,注意,%c前有一个空格
    fscanf(fp, "%d %c %d", &data1, &ch, &data2);
    if ('+'==ch)
    {
    
    
        result = data1 + data2;
        printf("%d + %d = %d\n", data1, data2, result);
    }
    else
    {
    
    
        result = data1 - data2;
        printf("%d - %d = %d\n", data1, data2, result);
    }
    //close file
    fclose(fp);

    return 0;
}

P321

/* 
编写一程序P321.C实现以下功能
  在文本文件Comp.txt里有需要计算结果的整数算式,每个算式占一行且文件中有多个(数量不确定)算式,运算类型只有“加法(+)”或者“减法(-)”且运算符前后至少有一个空格。
计算这些算式的结果并在屏幕上显示。
  单击此处下载程序运行时测试用的算式文件Comp.txt并保存到程序P321.C所在的文件夹且文件名保持不变。
编程可用素材:
printf("Line %03d:  %5d + %-5d = %-6d\n");
printf("Line %03d:  %5d - %-5d = %-6d\n");
  程序的运行效果应类似地如图1所示。

Line 001:    123 + 556   = 679
Line 002:    300 - 215   = 85
Line 003:   1001 - 18976 = -17975
Line 004:   9123 + 5156  = 14279
图1 程序运行效果示例(使用系统提供的测试用算式文件Comp.txt)
 */
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    
    
    int data1, data2;
    int result;
    char ch;
    int i = 1;
    FILE *fp;

    // open file
    if ((fp = fopen("Comp.txt", "r")) == NULL)
    {
    
    
        printf("Open file failure.\n");
        exit(0);
    }

    // read data
    while (!feof(fp))
    {
    
    
        fscanf(fp, "%d %c %d", &data1, &ch, &data2);
        if (!('+' == ch || '-' == ch)) // 如果读出来的不是运算符号,就终止
        {
    
    
            break;
        }

        if ('+' == ch)
        {
    
    
            result = data1 + data2;
            printf("Line %03d:  %5d + %-5d = %-6d\n", i, data1, data2, result);
        }
        else
        {
    
    
            result = data1 - data2;
            printf("Line %03d:  %5d - %-5d = %-6d\n", i, data1, data2, result);
        }
        ch = '\0';  // 每一次用完之后,就将运算符清空
        i++;
    }

    // close file
    fclose(fp);

    return 0;
}
/* 
    另一种思路,就是将fscanf的返回值拿来判断
    程序中用到fscanf、fprintf,为了判断异常,需要知道两个函数的返回值含义

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

            1.fscanf正常情况下返回从文件中读出的参数个数
                fscanf返回的是实际读取的数据个数,出错或者到结尾返回EOF。
            2.fprintf正常情况下返回写入文件的字节数
    注意细节:
            1. 在空白符这个意义上来讲,fscanf 对空格、制表符、换行符是一视同仁的,不加区分的;%s会跳过前面的空白符,但是不会跳过后面的空白符;%c不会跳过空白符。
            2. *表示读取一个域,但是不赋值给变量。
            3. []表示只读取中括号内的字符,[]表示不读取中括号内的字符,值得注意的是%[]s将不会跳过前面的空白符。
            4. 如果还没有任何一个域匹配成功或者任何一个匹配失败发生之前,就达到了文件流末尾,就算出错;或者读取文件流出错。这两种情况下,fscanf 返回EOF。
 */

P324

/* 
编写一程序P324.C实现以下功能
  在文本文件Comp.txt、CompA.txt、CompB.txt里有需要计算结果的整数算式,文件Comp.txt提供参加运算的第一个数,文件CompA.txt提供进行运算的运算符(只有“加法(+)”或者“减法(-)”),文件CompB.txt提供参加运算的第二个数,每个数或运算符均占一行,组合起来成为一个算式,遇到无法组成一个完整算式时即结束运算。这样的算式有多个(数量不确定)。计算这些算式的结果并在屏幕上显示。
  单击下载程序运行时测试用的算式文件Comp.txt、CompA.txt、CompB.txt并保存到程序P324.C所在的文件夹且文件名保持不变。
编程可用素材:
printf("Line %03d:  %5d %c %-5d = %-6d\n");
  程序的运行效果应类似地如图1所示。

Line 001:    123 + 556   = 679
Line 002:    300 - 215   = 85
Line 003:   1001 - 18976 = -17975
Line 004:   9123 + 5156  = 14279
图1 程序运行效果示例
*/
#include <stdio.h>

int main(void)
{
    
    
    int a1, a2; // 两个操作数
    char ch;    // 操作符
    int n = 1;  // 计数器

    // 文件操作指针
    FILE *fp1, *fp2, *fp3;
    fp1 = fopen("Comp.txt", "r");
    fp2 = fopen("CompA.txt", "r");
    fp3 = fopen("CompB.txt", "r");

    // 赋值后再判断,语句更简单一些
    if (fp1 == NULL || fp2 == NULL || fp3 == NULL)
    {
    
    
        printf("error\n");
        return 0;
    }

    while (!feof(fp2))  // 运算完成,首先要有运算符
    {
    
    
        // 充分利用返回值判断读取是否成功,三个数据要同时都有,才可以完成运算
        if ((fscanf(fp1, "%d", &a1) == 1) && (fscanf(fp2, " %c", &ch) == 1) && (fscanf(fp3, "%d", &a2) == 1))
        {
    
    
            if (ch == '+')
            {
    
    
                printf("Line %03d:  %5d %c %-5d = %-6d\n", n, a1, ch, a2, a1 + a2);
            }
            else
            {
    
    
                printf("Line %03d:  %5d %c %-5d = %-6d\n", n, a1, ch, a2, a1 - a2);
            }
            n++;    // 计数器
        }
        else        // 如果读取失败【即两个操作数和一个操作符,只要有一个未读到数据,就不再处理】
        {
    
    
            break;
        } 
    }

    // 要记得关闭文件
    fclose(fp1);
    fclose(fp2);
    fclose(fp3);
    
    return 0;
}

P325

/* 
编写一程序P325.C实现以下功能
  在文本文件Comp.txt、CompA.txt、CompB.txt里有需要计算结果的整数算式,
文件Comp.txt提供参加运算的第一个数,
文件CompA.txt提供进行运算的运算符(只有“加法(+)”或者“减法(-)”),
文件CompB.txt提供参加运算的第二个数,每个数或运算符均占一行,组合起来成为一个算式,遇到无法组成一个完整算式时即结束运算。
这样的算式有多个(数量不确定)。计算这些算式的结果并将结果以文本文件格式保存到程序P325.C所在的文件夹中且文件名命名为CompC.txt。
  单击下载程序运行时测试用的算式文件Comp.txt、CompA.txt、CompB.txt并保存到程序P325.C所在的文件夹且文件名保持不变。
编程可用素材:
fprintf(…"Line %03d:  %5d %c %-5d = %-6d\n");
  程序运行后生成的文件CompC.txt的内容应类似地如图1所示。

图1 程序运行效果示例(生成的文件CompC.txt之内容)
 */
#include <stdio.h>
#include <stdlib.h>

int main(int argc,char *argv[])
{
    
    
    int data1, data2, result;
    char ch;
    int i = 1;
    int r1, r2, r3; // 文件读取返回值

    FILE *fp1, *fp2, *fp3, *fp4;

    // 文件正常打开
    if ((fp1 = fopen("Comp.txt", "r"))==NULL)
    {
    
    
        printf("open file Comp.txt failure.\n");
        exit(0);
    }
    if ((fp2 = fopen("CompA.txt", "r"))==NULL)
    {
    
    
        printf("open file CompA.txt failure.\n");
        exit(0);
    }
    if ((fp3 = fopen("CompB.txt", "r"))==NULL)
    {
    
    
        printf("open file CompB.txt failure.\n");
        exit(0);
    }
    // 注意:这个文件是写数据
    if ((fp4 = fopen("CompC.txt", "w"))==NULL)
    {
    
    
        printf("open file CompC.txt failure.\n");
        exit(0);
    }

    while (!feof(fp2))   // 要有运算符号,才可以运算
    {
    
    
        r1 = fscanf(fp2, " %c", &ch);
        r2 = fscanf(fp1, "%d", &data1);
        r3 = fscanf(fp3, "%d", &data2);
        if ((r1 == 1) && (r2 == 1) && (r3 == 1))    //是否都成功读取了数据
        {
    
    
            if ('+' == ch)
            {
    
    
                result = data1 + data2;
                fprintf(fp4, "Line %03d:  %5d %c %-5d = %-6d\n", i, data1, ch, data2, result);
            }
            else
            {
    
    
                result = data1 - data2;
                fprintf(fp4, "Line %03d:  %5d %c %-5d = %-6d\n", i, data1, ch, data2, result);
            }
            i++;    // 计数器
        }
        else
        {
    
    
            break;
        }
    }

    // 关闭文件
    fclose(fp1);
    fclose(fp2);
    fclose(fp3);
    fclose(fp4);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/matrixbbs/article/details/111257550