TypechoJoeTheme

日志随记

统计
登录
用户名
密码

扫码登录
/
注册
用户名

此用户名将作为登录时所用的账号

邮箱

XG.孤梦

随风而动,随遇而安......

C语言读写程序文件-学习三十二

XG.孤梦博 主大佬
2022-02-27
/
0 评论
/
2,466 阅读
/
2150 个字
/
百度已收录
02/27
本文最后更新于 2022年08月13日,已超过 783天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!

顺序读写数据文件

  • 顺序写时,先写入的数据存放在文件中前面,后写入的数据存放在文件中后面
  • 顺序读时,先读文件中前面的数据,后读文件中后面的数据。
  • 顺序读写来说,对文件读写数据的顺序和数据文件中的物理顺序是一致的

读写一个字符的函数

  • fgetc()函数

    • 原型:int fgetc( FILE * fp );
    • 调用形式:fgetc(fp)
    • 作用:从 fp 所指向的输入文件中读取一个字符
    • 返回值:成功则返回的是读取的字符,发生错误则返回 EOF(即-1)。
  • fputc()函数

    • 原型:int fputc( int c, FILE *fp );
    • 调用形式:fputc(c,fp)
    • 功能:把参数 c 的字符值写入到 fp 所指向的输出流(文件)中
    • 返回值:写入成功,它会返回它会返回写入的字符(一个非负值),发生错误,则会返回 EOF(即-1)。
  • 例如:

从一个磁盘文本文件顺序读入字符并在屏幕上显示出来。

#include <stdio.h>
#include <string.h>

void main() {
    char c;
    FILE* fp = NULL;
    fopen_s(&fp, "a.txt", "r");
    c = fgetc(fp);
    while (c != EOF) {
        putchar(c);
        c = fgetc(fp);
    }
    fclose(fp);
}


  • feof()函数

    • 调用方式:feof(fp)
    • 功能:对于二进制文件读取时判断是否结束。
    • 返回值:如果是文件结束,函数feof()值为1(真);否则为0(假)。
  • 例如:

从一个磁盘二进制文件顺序读入字符并在屏幕上显示出来。

#include <stdio.h>
#include <string.h>

void main() {
    char c;
    FILE* fp = NULL;
    fopen_s(&fp, "a", "r");
    c = fgetc(fp);
    while (!feof(fp)) {
        putchar(c);
        c = fgetc(fp);
    }
    fclose(fp);
}


例子

从键盘输入一些字符,逐个把它们送到磁盘上去直到用户输入一个“#”为止。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)

void main() {
    char c,filename[10];
    FILE *fp = NULL;
    printf("请输入所用的文件名:");
    scanf("%s", filename);
    if ((fp = fopen(filename, "w")) == NULL) {
        printf("无法打开此文件\n");
        exit(0);
    }
    c = getchar(); // 接收执行scanf时最后输入的回车符
        // 如果注释掉,文件中会首先换行,然后再输入的字符串

    printf("请输入一个字符串(以#结束)");
        c = getchar(); // 第一个输入的字符被赋给变量c
        while (c!='#') {
            fputc(c, fp);
            putchar(c);  // 字符被输出到显示器
            c = getchar();
        }
        putchar(10); // 向屏幕输出一个换行符
    fclose(fp);
}


将一个磁盘文件中的信息复制到另一个磁盘文件中。今要求建立的a.txt文件中的内容复制到另一个磁盘文件b.txt中。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)


void main() {
    char c=NULL,infile[10],outfile[10];
    FILE *in = NULL;
    FILE *out = NULL;
    printf("请输入读取的文件名:");
    scanf("%s", infile);
    printf("请输入输出的文件名:");
    scanf("%s", outfile);
    if ((in = fopen(infile, "r")) == NULL) {
        printf("无法打开此文件\n");
        exit(0);
    }
    if ((out = fopen(outfile, "w")) == NULL) {
        printf("无法打开此文件\n");
        exit(0);
    }
    while (c!=EOF) {
        c= fgetc(in);
        fputc(c, out);
        putchar(c);  // 字符被输出到显示器
    }
    putchar(10); // 向屏幕输出一个换行符
    fclose(in);
    fclose(out);
}


读写一个字符串的函数

  • fgets()函数

    • 原型:char *fgets( char *buf, int n, FILE *fp );
    • 调用格式:char *fgets( str, n, fp );
    • 功能:从 fp 所指向的输入流(文件)中读取长度为(n - 1)的字符串存放到字符数组str中,并在最后追加一个 null 字符(即'\0')来终止字符串。
    • 返回值:读成功返回地址str ,失败则返回NULL
  • fputs()函数

    • 原型:int fputs( const char *s, FILE *fp );
    • 调用格式:int fputs( str, fp );
    • 功能:str所指向的字符串写到文件指针变量fp所指向的文件中。
    • 返回值:如果写入成功,则返回写出的字符个数(一个非负值),如果发生错误,则返回EOF(即-1)。
  • 说明:

    • fgets(str,n,fp);中 n 是要求得到的字符个数,但实际上只读 n-1 个字符,然后在最后加一个\0字符
      这样得到的字符串共有n个字符,把它们放到字符数组str中。
    • fgets()函数,如果在读完 n-1 个字符之前就遇到一个换行符 \n 或文件的末尾 EOF
      则读入结束,则只会返回读取到的字符,包括换行符
    • fputs函数中第一个参数可以是字符串常量、字符数组名或字符型指针。
    • fputs()函数字符串末尾的\0不输出。

例子

从键盘读入若千个字符串,然后把字符串送到磁盘文件中保存。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)

void main() {
    char str[3][10];
    int i;
    FILE *fp = NULL;
    printf("请输入要写入的字符串:\n");
    for (i = 0; i < 3; i++) {
        gets(str[i]);
    }
    if ((fp = fopen("a.txt", "w")) == NULL) {
        printf("无法打开此文件\n");
        exit(0);
    }
    for (i = 0; i < 3; i++) {
        fputs(str[i], fp);
        fputs("\n", fp);
        printf("写入成功:");
        printf("%s\n", str[i]);
    }
    fclose(fp);
}


读取文件中的字符串,打印到控制台

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)

void main() {
    char str[3][10];
    int i;
    FILE *fp = NULL;

    if ((fp = fopen("a.txt", "r")) == NULL) {
        printf("无法打开此文件\n");
        exit(0);
    }
    for (i = 0; i < 3; i++) {
        fgets(str[i],10,fp);
        printf("%s", str[i]);
    }
    fclose(fp);
}


用格式化的方式读写文件

  • 一般调用方式为:

    • fprintf(文件指针, 格式字符串, 输出表列);
    • 例如:

      • fprintf(fp,"%d,%f",i,f);
    • fscanf(文件指针, 格式字符串, 输入表列);
    • 例如:

      • fscanf(fp,"%d,%f",&i,&f);
  • 用fprintf和fscanf对磁盘文件读写,使用方便,容易理解,
    但是由于在输入时要将ASCII码转换为二进制形式,在输出时又要将二进制形式转换符,花费时间比较多。

    • 因此在内存与磁盘频繁交换的情况下,最好不要用 fprintf 和 fscanf 函数,可以用fread 和 fwrite 函数

二进制 I/O 函数

  • fread函数
  • 原型:size_t fread(void *buffer, size_t size, size_t count, FILE *a_file);
  • 返回值:如果读取成功,则返回读的块数,失败,则返回0 。
  • fwrite函数
  • 原型:size_t fwrite(const void *buffer, size_t size, size_t count, FILE *a_file);
  • 返回值:如果写入成功,则返回写的块数,失败,则返回0 。
  • 这两个函数都是用于存储块的读写 - 通常是数组或结构体。

例子:

从键盘输入5个学生的有关数据,然后把它们转存到磁盘文件上去,读取并打印到控制台。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)
#define SIZE 5

struct Student {
    int num;
    char name[10];
    int age;
    char addr[15];
}stu[SIZE];


void main() {
    void save();
    void reads();
    int i;
    printf("请输入学生数据:\n");
    for (i = 0; i < SIZE; i++) {
        scanf("%d %s %d %s", &stu[i].num, stu[i].name, &stu[i].age, stu[i].addr);
    }
    save();
    printf("学生信息:\n");
    reads();
}

void save() {
    int i;
    FILE *fp = NULL;

    if ((fp = fopen("stu.dat", "wb")) == NULL) {
        printf("无法打开此文件\n");
        return;
    }
    for (i = 0; i < SIZE; i++) {
        if (fwrite(&stu[i], sizeof(struct Student), 1, fp) != 1) {
            printf("写入文件错误\n");
        }
    }
    fclose(fp);
}

void reads() {
    int i;
    FILE *fp = NULL;

    if ((fp = fopen("stu.dat", "rb")) == NULL) {
        printf("无法打开此文件\n");
        return;
    }
    for (i = 0; i < SIZE; i++) {
        fread(&stu[i], sizeof(struct Student), 1, fp);
        printf("%4d %-10s %4d %-15s\n", stu[i].num, stu[i].name, stu[i].age, stu[i].addr);
    }
    fclose(fp);
}


从已有的二进制文件“stu2.dat”中,读入数据并输出到“stu.dat”文件中

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)
#define SIZE 7

struct Student {
    int num;
    char name[10];
    int age;
    char addr[15];
}stu[SIZE];


void main() {
    void load();
    void save();
    void reads();
    load();
    save();
    printf("学生信息:\n");
    reads();
}

void save() {
    int i;
    FILE *fp = NULL;

    if ((fp = fopen("stu.dat", "wb")) == NULL) {
        printf("无法打开此文件\n");
        return;
    }
    for (i = 0; i < SIZE; i++) {
        if (fwrite(&stu[i], sizeof(struct Student), 1, fp) != 1) {
            printf("写入文件错误\n");
        }
    }
    fclose(fp);
}

void reads() {
    int i;
    FILE *fp = NULL;

    if ((fp = fopen("stu.dat", "rb")) == NULL) {
        printf("无法打开此文件\n");
        return;
    }
    for (i = 0; i < SIZE; i++) {
        fread(&stu[i], sizeof(struct Student), 1, fp);
        printf("%4d %-10s %4d %-15s\n", stu[i].num, stu[i].name, stu[i].age, stu[i].addr);
    }
    fclose(fp);
}

void load() {
    int i;
    FILE *fp = NULL;

    if ((fp = fopen("stu2.dat", "rb")) == NULL) {
        printf("无法打开此文件\n");
        return;
    }
    for (i = 0; i < SIZE; i++) {
        if (fread(&stu[i], sizeof(struct Student), 1, fp) != 1) {
            if (feof(fp)) {
                fclose(fp);
                return;
            }
            printf("无法打开此文件\n");
        }
    }
    fclose(fp);
}


  • 其它读写函数

    • putw 和 getw 函数
    • 作用:以二进制形式,对磁盘文件读写一个int型的整数,2个字节。
    • 返回值:成功,则返回所写的整数值;失败,则返回EOF
    • 例如:putw(10, fp); i=getw(fp);

随机读写数据文件

  • 对文件进行顺序读写比较容易理解,也容易操作,但有时效率不高。

文件位置标记

  • 为了对读写进行控制,系统为每个文件设置了一个文件读写位置标记(简称文件标记),
    用来指示“接下来要读写的下一个字符的位置”。
  • 一般情况下,在对字符文件进行顺序读写时,文件标记指向文件开头,进行读的操作时,就读第一个字符,然后文件标记向后移动一个位置,在下一次读操作时,将位置标记指向第二个字符读入,以此类推直到遇文件尾结束。
  • 随机读写可以在任何位置读取和写入数据

文件位置标记的定位

  • 将文件的指针指向文件的开头,进行文件操作
  • rewind函数
  • 函数原型:void rewind(FILE *fp);
  • 功能:重置文件位置指针到文件开头。
  • 返回值:无

-例如:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)

void main(){ 
    FILE *fp1, *fp2;
    fp1 = fopen("file1.dat", "r");
    fp2 = fopen("file2.dat", "w");
    while (!feof(fp1)) {
        putchar(getc(fp1));
    }
    putchar(10);
    rewind(fp1); 
    while (!feof(fp1)) {
        putc(getc(fp1), fp2);
    }
    fclose(fp1);
    fclose(fp2); 
}


  • 可以强制使文件标记指向指定的位置
  • fseek函数
  • 调用形式:fseek(文件类型指针,位移量,起始点)
  • 起始点:0代表“文件开始位置(SEEK_SET)”,1为“文件当前位置(SEEK_CUR)”,2代表“文件的末尾(SEEK_END)”。
  • 位移量指以起始点为基点,向前移动的字节数。位移量应是long型数据(在数字的末尾加一个字母L)。
  • fseek函数一般用于二进制文件。
  • 例如:
    fseek(fp,100L,0);  // 将位置指针移动到离文件头100个字节处
    fseek(fp,50L,1);   // 离当前位置50个字节处
    fseek(fp,-10L,2);  // 从文件末尾处向后退10个字节

  • ftell函数
  • 由于文件中的文件位置标记经常移动,人们往往不容易知道其当前位置,所以常用ftell函数得到当前位置(相对于文件开头的位移量来表示)。
    如果调用函数时出错(如不存在fp指向的文件),ftell函数返回值为-1L。
  • 例如:

    • i=ftell(fp);
    • if(i==-1L){printf("error\n");}

例子

在磁盘文件上存有10个学生的数据要求将第1,3,5,7,9个学生数据输入计算机,并在控制台显示出来。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)

struct Student {
    int num;
    char name[10];
    int age;
}stu[10];

void main() {
    FILE *fp;
    int i;
    if ((fp = fopen("stu.dat", "rb")) == NULL) {
        printf("打开文件失败");
        exit(0);
    }
    for (i = 0; i < 10; i+=2) {
        fseek(fp, i * sizeof(struct Student), 0);
        fread(&stu[i], sizeof(struct Student), 1, fp);
        printf("%4d %-10s %4d\n", stu[i].num, stu[i].name, stu[i].age);
    }
    fclose(fp);
}


文件读写的出错检测

  • ferror函数

    • 一般调用形式:ferror(fp);
    • 返回值:如果为0,表示未出错,否则表示出错。
  • 每次调用输入输出函数,都产生新的ferror函数值,因此调用输入输出函数后立即检查。
  • 调用fopen时,ferror的初始值自动置为0。

  • clearerr函数

    • 作用是使文件错误标志和文件结束标志置为0。
  • 调用一个输入输出函数时出现错误(ferror值为非零值),立即调用clearerr(fp),
    使ferror(fp)值变0,以便再进行下一次检测
  • 只要出现文件读写错误标志,它就一直保留,直到对同一文件调用 clearerr 函数或 rewind 函数,或任何其他一个输入输出函数

总结

  • 在使用文件时,首先要定义一个文件指针:FILE *fp;
    然后通过该指针来操作相应的文件;
  • 通过fopen这个函数,使文件指针fp和相应的文件建立了联系,通过fclose函数将切断fp和文件的联系;
  • 如果以一次一个字符的方式处理文件,需要用 fgetc 或者 fputc 函数;
  • 如果以一次一行的方式处理文件,可以用 fgets 或者 fputs 函数;
  • 如果以一次一个结构体的方式处理文件,可以用 freadfwrite 函数(多为二进制文件);

学习笔记C语言
朗读
赞(0)
赞赏
感谢您的支持,我会继续努力哒!
版权属于:

日志随记

本文链接:

https://www.xggm.top/archives/760.html(转载时请注明本文出处及文章链接)

评论 (0)
 
登录
X
用户名
密码