C语言程序设计-13 文件

C语言程序设计的源码和书籍, 所有源码都是可执行的,整理不易家人们
https://kdocs.cn/join/gi76b0d?f=101 ➕绿泡泡:jianyuePros, 备注:C 程序设计;五个元子下载使用;
「《C 程序设计》(第五版)谭浩强主编,清华大学出版社,2017 年和源码」

13.1 C 文件概述

所谓“文件”是指一组相关数据的有序集合。这个数据集有一个名称,叫做文件名。实
际上在前面的各章中我们已经多次使用了文件,例如源程序文件、目标文件、可执行文件、
库文件 (头文件)等。
文件通常是驻留在外部介质(如磁盘等)上的,在使用时才调入内存中来。从不同的角度
可对文件作不同的分类。从用户的角度看,文件可分为普通文件和设备文件两种。
普通文件是指驻留在磁盘或其它外部介质上的一个有序数据集,可以是源文件、目标文
件、可执行程序;也可以是一组待输入处理的原始数据,或者是一组输出的结果。对于源文
件、目标文件、可执行程序可以称作程序文件,对输入输出数据可称作数据文件。
设备文件是指与主机相联的各种外部设备,如显示器、打印机、键盘等。在操作系统中,
把外部设备也看作是一个文件来进行管理,把它们的输入、输出等同于对磁盘文件的读和写。
通常把显示器定义为标准输出文件,一般情况下在屏幕上显示有关信息就是向标准输出
文件输出。如前面经常使用的 printf,putchar 函数就是这类输出。
键盘通常被指定标准的输入文件,从键盘上输入就意味着从标准输入文件上输入数据。
scanf,getchar 函数就属于这类输入。
从文件编码的方式来看,文件可分为 ASCII 码文件和二进制码文件两种。ASCII 文件也
称为文本文件,这种文件在磁盘中存放时每个字符对应一个字节,用于存放对应的 ASCII 码。
例如,数 5678 的存储形式为:
ASCII 码: 00110101 00110110 00110111 00111000
↓ ↓ ↓ ↓
十进制码: 5 6 7 8
共占用 4 个字节。
ASCII 码文件可在屏幕上按字符显示,例如源程序文件就是 ASCII 文件,用 DOS 命令 TYPE
可显示文件的内容。由于是按字符显示,因此能读懂文件内容。
二进制文件是按二进制的编码方式来存放文件的。
例如, 数 5678 的存储形式为:
00010110 00101110
只占二个字节。二进制文件虽然也可在屏幕上显示,但其内容无法读懂。C 系统在处理这些
文件时,并不区分类型,都看成是字符流,按字节进行处理。
输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。 因此也
把这种文件称作“流式文件”。
本章讨论流式文件的打开、关闭、读、写、 定位等各种操作。

13.2 文件指针

13.3 文件的打开与关闭

13.3.1 文件的打开(fopen 函数)

使用文件的方式共有 12 种,下面给出了它们的符号和意义。
在这里插入图片描述在这里插入图片描述

13.3.2 文件关闭函数(fclose 函数)

13.4 文件的读写

13.4.1 字符读写函数 fgetc 和 fputc

【例 13.1】读入文件 exception.log,在屏幕上输出。

#include <stdio.h>

int main() {
    // 文件指针
    FILE *file;
    // char filename[] = "temp11.7.c"; // 要读取的文件名
    char filename[] = "C:\\Users\\24682\\Downloads\\exception.log"; // 要读取的文件名
    // char filename[] = "F:\\ZhongJinHuiAn\\study\\c_study\\C-dev\\2024.06.02\\chaperEleven\\temp01\\temp11.7.c"; // 要读取的文件名
    char buffer[255]; // 用于存储读取到的文本的缓冲区

    // 使用 fopen 函数以读取模式打开文件
    file = fopen(filename, "r");
    if (file == NULL) { // 检查文件是否成功打开
        perror("Error opening file"); // 使用 perror 显示错误信息
        return 1; // 如果打开失败,退出程序
    }

    // 读取文件内容
    while (fgets(buffer, sizeof(buffer), file) != NULL) {
        // fgets 读取一行到缓冲区,包括换行符,直到文件结束或缓冲区满
        printf("%s", buffer); // 打印读取到的行
    }

    // 关闭文件
    fclose(file);

    printf("File read successfully.\n");
    return 0;
}

【例 13.2】从键盘输入一行字符,写入一个文件,再把该文件内容读出显示在屏幕上。

#include <stdio.h>
main()
{
    FILE *fp;
    char ch;
    if ((fp = fopen("C:\\Users\\24682\\Downloads\\2024062001.log", "rt")) == NULL)

    {
        printf("\nCannot open file strike any key exit!");
        getch();
        exit(1);
    }
    ch = fgetc(fp);
    while (ch != EOF)
    {
        putchar(ch);
        ch = fgetc(fp);
    }
    fclose(fp);
}

本例程序的功能是从文件中逐个读取字符,在屏幕上显示。程序定义了文件指针 fp,以
读文本文件方式打开文件“d:\jrzh\example\ex1_1.c”,并使 fp 指向该文件。如打开文
件出错,给出提示并退出程序。程序第 12 行先读出一个字符,然后进入循环,只要读出的字
符不是文件结束标志(每个文件末有一结束标志 EOF)就把该字符显示在屏幕上,再读入下一
字符。每读一次,文件内部的位置指针向后移动一个字符,文件结束时,该指针指向 EOF。
执行本程序将显示整个文件。

2. 写字符函数 fputc

【例 13.2】从键盘输入一行字符,写入一个文件,再把该文件内容读出显示在屏幕上。

#include <stdio.h>

main()
{
    FILE *fp;
    char ch;
    if ((fp = fopen("C:\\Users\\24682\\Downloads\\2024062002.log", "wt+")) == NULL)
    {
        printf("Cannot open file strike any key exit!");
        getch();
        exit(1);
    }
    printf("input a string:\n");
    ch = getchar();
    while (ch != '\n')
    {
        fputc(ch, fp);
        ch = getchar();
    }
    rewind(fp);
    ch = fgetc(fp);
    while (ch != EOF)
    {
        putchar(ch);
        ch = fgetc(fp);
    }
    printf("\n");
    fclose(fp);
}

程序中第 6 行以读写文本文件方式打开文件 string。程序第 13 行从键盘读入一个字符
后进入循环,当读入字符不为回车符时,则把该字符写入文件之中,然后继续从键盘读入下
一字符。每输入一个字符,文件内部位置指针向后移动一个字节。写入完毕,该指针已指向
文件末。如要把文件从头读出,须把指针移向文件头,程序第 19 行 rewind 函数用于把 fp
所指文件的内部位置指针移到文件头。第 20 至 25 行用于读出文件中的一行内容。

【例 13.3】把命令行参数中的前一个文件名标识的文件,复制到后一个文件名标识的文件中,
如命令行中只有一个文件名则把该文件写到标准输出文件(显示器)中。

#include <stdio.h>
#include <stdlib.h>

main(int argc, char *argv[])
{
    FILE *fp1, *fp2;
    char ch;
    if (argc == 1)
    {
        printf("have not enter file name strike any key exit");
        getch();
        exit(0);
    }
    if ((fp1 = fopen(argv[1], "rt")) == NULL)
    {
        printf("Cannot open %s\n", argv[1]);
        getch();
        exit(1);
    }
    if (argc == 2)
        fp2 = stdout;
    else if ((fp2 = fopen(argv[2], "wt+")) == NULL)
    {
        printf("Cannot open %s\n", argv[1]);
        getch();
        exit(1);
    }
    while ((ch = fgetc(fp1)) != EOF)
        fputc(ch, fp2);
    fclose(fp1);
    fclose(fp2);
}

执行:
./temp13.3.exe C:\Users\24682\Downloads\exception.log C:\Users\24682\Downloads\2024062002.log

本程序为带参的 main 函数。程序中定义了两个文件指针 fp1 和 fp2,分别指向命令行参
数中给出的文件。如命令行参数中没有给出文件名,则给出提示信息。程序第 18 行表示如果
只给出一个文件名,则使 fp2 指向标准输出文件(即显示器)。程序第 25 行至 28 行用循环语
句逐个读出文件 1 中的字符再送到文件 2 中。再次运行时,给出了一个文件名,故输出给标
准输出文件 stdout,即在显示器上显示文件内容。第三次运行,给出了二个文件名,因此把
string 中的内容读出,写入到 OK 之中。可用 DOS 命令 type 显示 OK 的内容。

13.4.2 字符串读写函数 fgets 和 fputs

1. 读字符串函数 fgets

【例 13.4】从 string 文件中读入一个含 10 个字符的字符串。

#include <stdio.h>
#include <stdlib.h>

main()
{
    FILE *fp;
    char str[11];
    if ((fp = fopen("C:\\Users\\24682\\Downloads\\2024062002.log", "rt")) == NULL)
    {
        printf("\nCannot open file strike any key exit!");
        getch();
        exit(1);
    }
    fgets(str, 11, fp);
    printf("\n%s\n", str);
    fclose(fp);
}

本例定义了一个字符数组 str 共 11 个字节,在以读文本文件方式打开文件 string 后,
从中读出 10 个字符送入 str 数组,在数组最后一个单元内将加上’\0’,然后在屏幕上显示输
出 str 数组。输出的十个字符正是例 13.1 程序的前十个字符。
对 fgets 函数有两点说明:

  1. 在读出 n-1 个字符之前,如遇到了换行符或 EOF,则读出结束。
  2. fgets 函数也有返回值,其返回值是字符数组的首地址。
2. 写字符串函数 fputs

【例 13.5】在例 13.2 中建立的文件 string 中追加一个字符串。

#include <stdio.h>
#include <stdlib.h>

main()
{
    FILE *fp;
    char ch, st[20];
    if ((fp = fopen("string", "at+")) == NULL)
    {
        printf("Cannot open file strike any key exit!");
        getch();
        exit(1);
    }
    printf("input a string:\n");
    scanf("%s", st);
    fputs(st, fp);
    rewind(fp);
    ch = fgetc(fp);
    while (ch != EOF)
    {
        putchar(ch);
        ch = fgetc(fp);
    }
    printf("\n");
    fclose(fp);
}

本例要求在 string 文件末加写字符串,因此,在程序第 6 行以追加读写文本文件的方式
打开文件 string。然后输入字符串,并用 fputs 函数把该串写入文件 string。在程序 15 行
用 rewind 函数把文件内部位置指针移到文件首。再进入循环逐个显示当前文件中的全部内
容。

13.4.3 数据块读写函数 fread 和 fwtrite

【例 13.6】从键盘输入两个学生数据,写入一个文件中,再读出这两个学生的数据显示在屏
幕上。

#include <stdio.h>
#include <stdlib.h>

struct stu
{
    char name[10];
    int num;
    int age;
    char addr[15];
} boya[2], boyb[2], *pp, *qq;

main()
{
    FILE *fp;
    char ch;
    int i;
    pp = boya;
    qq = boyb;
    if ((fp = fopen("C:\\Users\\24682\\Downloads\\2024062002.log", "wb+")) == NULL)
    {
        printf("Cannot open file strike any key exit!");
        getch();
        exit(1);
    }
    printf("\ninput data\n");
    for (i = 0; i < 2; i++, pp++)
        scanf("%s%d%d%s", pp->name, &pp->num, &pp->age, pp->addr);
    pp = boya;
    fwrite(pp, sizeof(struct stu), 2, fp);
    rewind(fp);
    fread(qq, sizeof(struct stu), 2, fp);
    printf("\n\nname\tnumber age addr\n");
    for (i = 0; i < 2; i++, qq++)
        printf("%s\t%5d%7d %s\n", qq->name, qq->num, qq->age, qq->addr);
    fclose(fp);
}

本例程序定义了一个结构 stu,说明了两个结构数组 boya 和 boyb 以及两个结构指针变量
pp 和 qq。pp 指向 boya,qq 指向 boyb。程序第 16 行以读写方式打开二进制文件“stu_list”,
输入二个学生数据之后,写入该文件中,然后把文件内部位置指针移到文件首,读出两块学
生数据后,在屏幕上显示。

13.4.4 格式化读写函数 fscanf 和 fprintf

【例 13.7】用 fscanf 和 fprintf 函数成例 10.6 的问题。

#include <stdio.h>
#include <stdlib.h>

struct stu
{
    char name[10];
    int num;
    int age;
    char addr[15];
} boya[2], boyb[2], *pp, *qq;
main()
{
    FILE *fp;
    char ch;
    int i;
    pp = boya;
    qq = boyb;
    if ((fp = fopen("stu_list", "wb+")) == NULL)
    {
        printf("Cannot open file strike any key exit!");
        getch();
        exit(1);
    }
    printf("\ninput data\n");
    for (i = 0; i < 2; i++, pp++)
        scanf("%s%d%d%s", pp->name, &pp->num, &pp->age, pp->addr);
    pp = boya;
    for (i = 0; i < 2; i++, pp++)
        fprintf(fp, "%s %d %d %s\n", pp->name, pp->num, pp->age, pp->addr);
    rewind(fp);
    for (i = 0; i < 2; i++, qq++)
        fscanf(fp, "%s %d %d %s\n", qq->name, &qq->num, &qq->age, qq->addr);
    printf("\n\nname\tnumber age addr\n");
    qq = boyb;
    for (i = 0; i < 2; i++, qq++)
        printf("%s\t%5d %7d %s\n", qq->name, qq->num, qq->age,
               qq->addr);
    fclose(fp);
}

与例 10.6 相比,本程序中 fscanf 和 fprintf 函数每次只能读写一个结构数组元素,因
此采用了循环语句来读写全部数组元素。还要注意指针变量 pp,qq 由于循环改变了它们的值,
因此在程序的 25 和 32 行分别对它们重新赋予了数组的首地址。

13.5 文件的随机读写

13.5.1 文件定位

13.5.2 文件的随机读写

【例 13.8】在学生文件 stu_list 中读出第二个学生的数据。

#include <stdio.h>
#include <stdlib.h>

struct stu
{
    char name[10];
    int num;
    int age;
    char addr[15];
} boy, *qq;
main()
{
    FILE *fp;
    char ch;
    int i = 1;
    qq = &boy;
    if ((fp = fopen("stu_list", "rb")) == NULL)
    {
        printf("Cannot open file strike any key exit!");
        getch();
        exit(1);
    }
    rewind(fp);
    fseek(fp, i * sizeof(struct stu), 0);
    fread(qq, sizeof(struct stu), 1, fp);
    printf("\n\nname\tnumber age addr\n");
    printf("%s\t%5d %7d %s\n", qq->name, qq->num, qq->age,
           qq->addr);
}

文件 stu_list 已由例 13.6 的程序建立,本程序用随机读出的方法读出第二个学生的数
据。程序中定义 boy 为 stu 类型变量,qq 为指向 boy 的指针。以读二进制文件方式打开文件,
程序第 22 行移动文件位置指针。其中的 i 值为 1,表示从文件头开始,移动一个 stu 类型的
长度,然后再读出的数据即为第二个学生的数据。

13.6 文件检测函数

13.6.1 文件结束检测函数 feof 函数

13.6.2 读写文件出错检测函数

13.6.3 文件出错标志和文件结束标志置 0 函数

13.7 C库文件

C系统提供了丰富的系统文件,称为库文件,C 的库文件分为两类,一类是扩展名为".h"
的文件,称为头文件,在前面的包含命令中我们已多次使用过。在".h"文件中包含了常量定
义、 类型定义、宏定义、函数原型以及各种编译选择设置等信息。另一类是函数库,包括了
各种函数的目标代码,供用户在程序中调用。 通常在程序中调用一个库函数时,要在调用之
前包含该函数原型所在的".h" 文件。
下面给出 Turbo C 的全部".h"文件。
Turbo C 头文件

		ALLOC.H 说明内存管理函数(分配、释放等)。 
		ASSERT.H 定义 assert 调试宏。 
		BIOS.H 说明调用 IBM—PC ROM BIOS 子程序的各个函数。 
		CONIO.H 说明调用 DOS 控制台 I/O 子程序的各个函数。 
		CTYPE.H 包含有关字符分类及转换的名类信息(如 isalpha 和 toascii 等)。 
		DIR.H 包含有关目录和路径的结构、宏定义和函数。 
		DOS.H 定义和说明 MSDOS 和 8086 调用的一些常量和函数。 
		ERRON.H 定义错误代码的助记符。 
		FCNTL.H 定义在与 open 库子程序连接时的符号常量。 
		FLOAT.H 包含有关浮点运算的一些参数和函数。 
		GRAPHICS.H 说明有关图形功能的各个函数,图形错误代码的常量定义,正对不同
		驱动程序的各种颜色值,及函数用到的一些特殊结构。 
		IO.H 包含低级 I/O 子程序的结构和说明。 
		LIMIT.H 包含各环境参数、编译时间限制、数的范围等信息。 
		MATH.H 说明数学运算函数,还定了 HUGE VAL 宏, 说明了 matherr 和
		matherr 子程序用到的特殊结构。 
		MEM.H 说明一些内存操作函数(其中大多数也在 STRING.H 中说明)。 
		PROCESS.H 说明进程管理的各个函数,spawn…和 EXEC …函数的结构说明。 
		SETJMP.H 定义 longjmp 和 setjmp 函数用到的 jmp buf 类型,说明这两个函数。 
		SHARE.H 定义文件共享函数的参数。 
		SIGNAL.H 定义 SIG[ZZ(Z] [ZZ)]IGN 和 SIG[ZZ(Z] [ZZ)]DFL 常量,说明
		rajse 和 signal 两个函数。 
		STDARG.H 定义读函数参数表的宏。(如 vprintf,vscarf 函数)。 
		STDDEF.H 定义一些公共数据类型和宏。 
		STDIO.H 定义 Kernighan 和 Ritchie 在 Unix System V 中定义的标准和扩展
		的类型和宏。还定义标准 I/O 预定义流:stdin,stdout 和 stderr,说明 I/O 流子
		程序。 
		STDLIB.H 说明一些常用的子程序:转换子程序、搜索/ 排序子程序等。 
		STRING.H 说明一些串操作和内存操作函数。 
		SYS\STAT.H 定义在打开和创建文件时用到的一些符号常量。 
		SYS\TYPES.H 说明 ftime 函数和 timeb 结构。 
		SYS\TIME.H 定义时间的类型 time[ZZ(Z] [ZZ)]t。
		„ TIME.H 定义时间转换子程序 asctime、localtime 和 gmtime 的结构,ctime、difftime、 gmtime、 localtime 和 stime 用到的类型,并提供这些函数的原型。 
		VALUE.H 定义一些重要常量,包括依赖于机器硬件的和为与 Unix System V 相兼容而说明的一些常量,包括浮点和双精度值的范围。

13.8 本章小结

  1. C系统把文件当作一个“流”,按字节进行处理。
  2. C文件按编码方式分为二进制文件和 ASCII 文件。
  3. C语言中,用文件指针标识文件,当一个文件被 打开时,可取得该文件指针。
  4. 文件在读写之前必须打开,读写结束必须关闭。
  5. 文件可按只读、只写、读写、追加四种操作方式打开,同时还必须指定文件的类型是
    二进制文件还是文本文件。
  6. 文件可按字节,字符串,数据块为单位读写,文件也可按指定的格式进行读写。
  7. 文件内部的位置指针可指示当前的读写位置,移动该指针可以对文件实现随机读写。

问题

问题1

如何读取中文文件的目录 ### 13.4.1 字符读写函数 fgetc 和 fputc

  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

java我跟你拼了

您的鼓励是我创作的最大动力!

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

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

打赏作者

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

抵扣说明:

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

余额充值