C语言文件操作

8/28/2023 C语言

# C 语言文件操作

# 什么是文件

磁盘上的文件。

# 程序文件

  • 源文件(.c)
  • 目标文件(windows为.obj)
  • 可执行程序(windows为.exe)

# 数据文件

程序运行时读写的数据。

# 文件的打开和关闭

# 文件指针

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息,这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE。

关于FILE结构在VC6中有如下定义:

struct _iobuf {
    char *_ptr; //文件输入的下一个位置
    int _cnt; //当前缓冲区的相对位置
    char *_base; //指基础位置(即是文件的起始位置) 
    int _flag; //文件标志
    int _file; //文件描述符id
    int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取
    int _bufsiz; //文件缓冲区大小
    char *_tmpfname; //临时文件名
       };
typedef struct _iobuf FILE;

# fopen

FILE * fopen ( const char * filename, const char * mode );

mode

  • r: 读
  • w: 写,会清空原内容
  • a: 追加
  • r+: 读/写,如果制定文件不存在,出错
  • w+: 读/写,如果制定文件不存在,建立一个新文件
  • a+: 追加写
  • rb: 以二进制读
  • wb: 以二进制写

# fclose

int fclose ( FILE * stream );

# 文件的顺序读写

fgetc

fputc

fgets

fputs

fscanf

fprintf

sprintf

sscanf

fwrite

fread

....

写文件

 #include <stdio.h>

int main() {
    // 打开文件
    FILE *pf = fopen("/Users/mac/code/比特C语言/text.txt", "w");

    if (pf == NULL) {
        perror("fopen");
        return 1;
    }

    // 写文件
    // 写一个字符
    fputc('a', pf);
    fputc('b', pf);
		// 写一行
    fputs("qwer", pf);

    // 关闭文件
    fclose(pf);
    pf = NULL;

    return 0;
}

读文件

#include <stdio.h>

int main() {
    // 打开文件
    FILE *pf = fopen("/Users/mac/code/比特C语言/text.txt", "r");

    if (pf == NULL) {
        perror("fopen");
        return 1;
    }

    // 读文件
    // 读一个字符
    // int ch;
    // while ((ch = fgetc(pf)) != EOF) {
    //    printf("%c ", ch);
    //}

    // 读一行
    char str[] = {0};
    // 实际上只读6个字符,要预留一个位置给'\0'
    while (fgets(str, 7, pf) != NULL) {
        printf("%s\n", str);
    }

    // 关闭文件
    fclose(pf);
    pf = NULL;

    return 0;
}

将格式化数据写入到文件

#include <stdio.h>

struct S {
    char name[20];
    int  age;
    double score;
};

int main() {
    struct S s = {"Bob", 20, 80};

    // 打开文件
    FILE *pf = fopen("/Users/mac/code/比特C语言/text.txt", "w");

    if (pf == NULL) {
        perror("fopen");
        return 1;
    }

    // 写文件
    fprintf(pf, "%s %d %lf", s.name, s.age, s.score);

    // 关闭文件
    fclose(pf);
    pf = NULL;

    return 0;
}

将文件数据读出到格式化数据

#include <stdio.h>

struct S {
    char name[20];
    int age;
    double score;
};

int main() {
    struct S s = {0};

    // 打开文件
    FILE *pf = fopen("/Users/mac/code/比特C语言/text.txt", "r");

    if (pf == NULL) {
        perror("fopen");
        return 1;
    }

    // 写文件
    fscanf(pf, "%s %d %lf", s.name, &(s.age), &(s.score));

    printf("%s %d %lf", s.name, s.age, s.score);
    // 关闭文件
    fclose(pf);
    pf = NULL;

    return 0;
}

把格式化数据转换为字符串

#include <stdio.h>

struct S {
    char name[20];
    int age;
    double score;
};

int main() {
    struct S s = {"Bob", 20, 80};
    char str[256] = {0};

    sprintf(str, "%s %d %lf", s.name, s.age, s.score);

    printf("%s\n", str);

    return 0;
}

把字符串转换为格式化数据

#include <stdio.h>

struct S {
    char name[20];
    int age;
    double score;
};

int main() {
    struct S s = {0};
    char str[256] = "Bob 20 80.0";

    sscanf(str, "%s %d %lf", s.name, &(s.age), &(s.score));

    printf("%s %d %lf", s.name, s.age, s.score);

    return 0;
}

以二进制的形式写入数据

#include <stdio.h>

struct S {
    char name[20];
    int age;
    double score;
};

int main() {
    struct S s = {"Bob", 20, 80};

    // 打开文件
    FILE *pf = fopen("/Users/mac/code/比特C语言/text.txt", "wb");

    if (pf == NULL) {
        perror("fopen");
        return 1;
    }

    // 写文件
    fwrite(&s,sizeof(struct S), 1, pf);

    // 关闭文件
    fclose(pf);
    pf = NULL;

    return 0;
}

以二进制的形式读出数据

#include <stdio.h>

struct S {
    char name[20];
    int age;
    double score;
};

int main() {
    struct S s = {0};

    // 打开文件
    FILE *pf = fopen("/Users/mac/code/比特C语言/text.txt", "rb");

    if (pf == NULL) {
        perror("fopen");
        return 1;
    }

    // 写文件
    fread(&s,sizeof(struct S), 1, pf);
    printf("%s %d %lf", s.name, s.age, s.score);
    
    // 关闭文件
    fclose(pf);
    pf = NULL;

    return 0;
}

# 文件的随机读写

# fseek

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

根据文件指针的位置和偏移量来定位文件指针

origin:

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

如果成功,该函数返回零。 否则,它返回非零值。

#include <stdio.h>

int main() {
    // 打开文件
    // text.txt: abcdef
    FILE *pf = fopen("/Users/mac/code/比特C语言/text.txt", "r");

    int ch = fgetc(pf);
    printf("%c\n", ch); // a
    ch = fgetc(pf);
    printf("%c\n", ch); // b

    fseek(pf, -1, SEEK_CUR);
    ch = fgetc(pf);
    printf("%c\n", ch); // b
    fseek(pf, 1, SEEK_CUR);
    ch = fgetc(pf);
    printf("%c\n", ch); // d

    fseek(pf, -1, SEEK_END);
    ch = fgetc(pf);
    printf("%c\n", ch); // f

    fseek(pf, 1, SEEK_SET);
    ch = fgetc(pf);
    printf("%c\n", ch); // b

    fclose(pf);
    pf = NULL;

    return 0;
}

# ftell

long int ftell ( FILE * stream );

返回文件指针相对于起始位置的偏移量

# rwind

void rewind ftell ( FILE * stream );

让文件指针回到文件的起始位置

# 文本文件和二进制文件

数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是我二进制文件。

如果要求在外存上以ASCII码的形式存储,则需要在存储前转换,以ASCII码的形式存储的文件就是文本文件。

![image-20230829144344305](/Users/mac/Library/Application Support/typora-user-images/image-20230829144344305.png)

# 文件读取结束的判定

# feof

当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。

  1. 文本文件读取是否结束,判断返回值是否为EOF或者NULL

    例如:fgetc判断是否为EOF,fgets判断返回值是否为NULL

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

    例如:fread判断返回值是否小于实际要读的个数

// 判断是什么原因结束的
if(ferrror(fp))
  puts("I/O error when reading");
else if(feof(fp))
  puts("End of file reached successfully");

# 文件缓冲区

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

![image-20230829152231415](/Users/mac/Library/Application Support/typora-user-images/image-20230829152231415.png)

Last Updated: 3/20/2024, 8:15:43 AM
강남역 4번 출구
Plastic / Fallin` Dild