文件操作

文件类型

数据文件分为文本文件和二进制文件。
数据在内存中以二进制的形式存储,如果不加以转换的输出到外存,就是二进制文件。
以ASCII字符的形式存储的文件就是文本文件。

123456789
#include <stdio.h>int main() {    int a = 10000;    FILE* pf = fopen("test.txt", "wb");//wb的意思是以二进制的形式写文件text.txt    fwrite(&a, 4, 1, pf);    fclose(pf);    pf = NULL;    return 0;}

文件指针

一般通过FILE的指针来维护这个FILE结构的变量。
文件指针变量:FILE* pf

文件打开关闭

文件在读写之前先打开文件,在使用结束之后关闭文件。
在编写程序时,在打开文件的同时,会返回一个FILE*类型的指针变量指向该文件。
fopen打开文件,用fclose关闭文件。
FILE* fopen (const char *filename, const char* mode);
int fclose (FILE* stream);

文件打开方式:

文件使用方式含义如果指定文件不存在
“r”(只读)为了输入文件,打开一个已经存在的文本文件出错
“w”(只写)为了输出数据,打开一个文本文件建立新文件
“a”(追加)向文本末尾添加数据出错
“rb”(只读)为了输入数据,打开一个二进制文件出错
“wb”(只写)为了输出数据,打开一个二进制文件建立新文件
“ab”(追加)向一个二进制文件尾添加数据出错
“r+”(读写)为了读和写,打开一个文本文件出错
“w+”(读写)为了读和写,建立一个新文件建立新文件
“a+”(读写)打开一个文件,在文件尾读写建立新文件
“rb+”(读写)为了读和写,打开一个二进制文件出错
“wb+”(读写)为了读和写,新建一个二进制文件建立新文件
“ab+”(读写)打开一个二进制文件,在文件尾进行读写建立新文件
12345678910111213141516171819
#include <stdio.h>#include <string.h>#include <errno.h>int main(){    //打开文件text.txt    FILE* pf = fopen("test.txt", "w");    if (pf == NULL)//打开失败    {        printf("%s\n",strerror(errno));        return 0;    }    //打开成功    //读文件    //关闭文件    fclose(pf);    pf = NULL;    return 0;}

文件的顺序读写

功能函数名适用于
字符输入函数fgetc所有输入流
字符输出函数fputc所有输出流
文本行输入函数fgets所有输入流
文本行输出函数fputs所有输出流
格式化输入函数fscanf所有输入流
格式化输出函数fprintf所有输出流
二进制输入fread文件
二进制输出fwrite文件

fputc

字符输出。
int fputc ( int character, FILE * stream );

123456789101112131415161718192021
#include <stdio.h>#include <string.h>#include <errno.h>int main(){    FILE* pfWrite = fopen("test.txt", "w");    if (pfWrite == NULL) {        printf("%s\n",strerror(errno));        return 0;    }    //写文件    fputc('H', pfWrite);    fputc('e', pfWrite);    fputc('l', pfWrite);    fputc('l', pfWrite);    fputc('o', pfWrite);    //关闭文件    fclose(pfWrite);    pfWrite = NULL;    return 0;}

程序运行后,test.txt内容改为Hello。先前的内容被抹去。
fputc一次会写入一个字符。

fgetc

字符输入。
int fgetc ( FILE * stream );

123456789101112131415161718192021
#include <stdio.h>#include <string.h>#include <errno.h>int main(){    FILE* pfRead = fopen("test.txt", "r");    if (pfRead == NULL) {        printf("%s\n",strerror(errno));        return 0;    }    //读文件    printf("%c",fgetc(pfRead));//H    printf("%c",fgetc(pfRead));//e    printf("%c",fgetc(pfRead));//l    printf("%c",fgetc(pfRead));//l    printf("%c",fgetc(pfRead));//0    //关闭文件    fclose(pfRead);    pfRead = NULL;    return 0;}

fgetc一次读一个字符。
test.txt的内容是:Hello

fgets

文本行输入。
char * fgets ( char * str, int num, FILE * stream );

12345678910111213141516171819202122
#include <stdio.h>#include <string.h>#include <errno.h>int main(){    char buf[1024] = {1};    FILE* pf = fopen("test.txt", "r");    if (pf == NULL)     {        printf("%s\n",strerror(errno));        return 0;    }    //读文件    fgets(buf,1024,pf);//fgets会读取到最后的换行符,所以打印时不用加\n就会换行,加了\n就换两行    printf("%s",buf);//Hello    fgets(buf,1024,pf);    printf("%s",buf);//World    //关闭文件    fclose(pf);    pf = NULL;    return 0;}

text.txt原先的内容是:

12
HelloWorld

一个fgets会读取一行文本至最后,fgets会读取到最后的换行符,所以打印时不用加\n就会换行,加了\n就换两行。
想要读取两行文本,就用两个fgets

fputs

文本行输出。
int fputs(const char *string,FILE *stream);

12345678910111213141516171819
#include <stdio.h>#include <string.h>#include <errno.h>int main(){    char buf[1024] = {0};    FILE* pf = fopen("test.txt", "w");    if (pf == NULL) {        printf("%s\n",strerror(errno));        return 0;    }    //写文件    fputs("hello\n", pf);    fputs("world", pf);    //关闭文件    fclose(pf);    pf = NULL;    return 0;}

运行程序后,test.txt的内容为:

12
helloworld

使用fputs函数,想在文件中换行需要自己输入\n

12345678910
#include <stdio.h>#include <string.h>#include <errno.h>int main(){    char buf[1024] = {0};    fgets(buf,1024,stdin);//从标准输入流读取信息(键盘)    fputs(buf, stdout);//输出到标准输出流(屏幕)    return 0;}

fscanf

格式化的输入数据。
int fscnaf(FILE *stream,const char *format[,arguments]...);

1234567891011121314151617181920212223
#include <stdio.h>#include <string.h>#include <errno.h>struct S{    int n;    float f;    char arr[10];};int main(){    struct S s = {0};    FILE* pf = fopen("test.txt", "r");    if (pf == NULL) {        return 0;    }    //以格式化输入数据    fscanf(pf, "%d %f %s",&(s.n),&(s.f),&(s.arr));    printf("%d %f %s\n",s.n,s.f,s.arr);    fclose(pf);    pf = NULL;    return 0;}

test.txt的内容是:100 3.140000 Hello
程序运行后,屏幕上输出:100 3.140000 Hello

123456789101112131415
#include <stdio.h>#include <string.h>#include <errno.h>struct S{    int n;    float f;    char arr[10];};int main(){    struct S s ={ 0 };    fscanf(stdin, "%d %f %s",&(s.n),&(s.f),&(s.arr));//从标准输入流获取数据(键盘)    fprintf(stdout, "%d %f %s",s.n,s.f,s.arr);//从标准输出流输出数据(屏幕)}

fprintf

以格式化的形式写文件。
int fprintf ( FILE * stream, const char * format, ... );

1234567891011121314151617181920212223
#include <stdio.h>#include <string.h>#include <errno.h>struct S{    int n;    float f;    char arr[10];};int main(){    struct S s = {100,3.14,"Hello"};    FILE* pf = fopen("test.txt", "w");    if (pf == NULL)     {        return 0;    }    //以格式化的形式写文件    fprintf(pf, "%d %f %s",s.n,s.f,s.arr);    fclose(pf);    pf = NULL;    return 0;}

程序运行后,test.txt被改为:100 3.140000 Hello

fread

以二进制的形式读文件。
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

1234567891011121314151617181920212223
#include <stdio.h>#include <string.h>#include <errno.h>struct S{    char name[20];    int age;    double score;};int main(){    struct S s ={ 0 };    FILE* pf = fopen("test.txt", "rb");    if (pf == NULL) {        return 0;    }    //二进制形式读文件    fread(&s, sizeof(struct S), 1, pf);    printf("%s %d %lf\n",s.name,s.age,s.score);    fclose(pf);    pf = NULL;    return 0;}

test.txt的内容为张三 12 111.999000
输出的结果是张三 12 111.999000

fwirte

以二进制的形式写文件。
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

1234567891011121314151617181920212223
#include <stdio.h>#include <string.h>#include <errno.h>struct S{    char name[20];    int age;    double score;};int main(){    struct S s = {"张三",12,111.999};    FILE* pf = fopen("test.txt", "w");    if (pf == NULL)     {        return 0;    }    //二进制形式写文件    fwrite(&s, sizeof(struct S), 1, pf);    fclose(pf);    pf = NULL;    return 0;}

程序运行后,test.txt的内容被改为张三 12 111.999000

文件的随机读写

fseek

根据文件指针的位置和偏移量来定位文件指针。
int fseek (FILE* stream , long int offset , int origin );
long int offset是偏移量,int origin是文件指针的当前位置。

test.txt文件的内容是abcdef

123456789101112131415161718
#include <stdio.h>#include <string.h>#include <errno.h>int main(){    FILE* pf = fopen("test.txt", "r");    if (pf == NULL)     {        return 0;    }    //1、定位文件指针    fseek(pf, 1, SEEK_CUR);    //2、读取文件    int ch = fgetc(pf);    printf("%c\n",ch);//b    fclose(pf);    pf = NULL;}

ftell

返回文件指针相对于起始位置的偏移量。
long int ftell (FILE *stream);

12345678910111213141516
#include <stdio.h>#include <string.h>#include <errno.h>int main(){    FILE* pf = fopen("test.txt", "r");    if (pf == NULL) {        return 0;    }    fgetc(pf);    //读取文件    int pos = ftell(pf);    printf("%d\n",pos);    fclose(pf);    pf = NULL;}

打印的结果是1

rewind

让文件指针位置回到文件的起始位置
void rewind (FILE* stream);

test.txt文件的内容是abcdef

123456789101112131415161718
#include <stdio.h>#include <string.h>#include <errno.h>int main(){    FILE* pf = fopen("test.txt", "r");    if (pf == NULL) {        return 0;    }    int ch = fgetc(pf);//读取的结果是a    printf("%c ",ch);    //2、读取文件    rewind(pf);    ch = fgetc(pf);//还是a    printf("%c ",ch);    fclose(pf);    pf = NULL;}

文件结束的判定

被错误使用的feof

在文件读取的过程中,不能用feof的返回值判断文件是否读取结束。
这个函数是用于当文件读取结束时,判断时读取失败结束,还是遇到文件尾结束。

test.txt文件的内容是abcdef

12345678910111213141516171819202122232425
#include <stdio.h>#include <string.h>#include <errno.h>int main(){    FILE* pf = fopen("test.txt", "r");    if (pf == NULL) {        perror("open file test.txt");        return 0;    }    int ch = 0;    while ((ch = fgetc(pf)) != EOF)    {        putchar(ch);    }    if (ferror(pf)) {        printf("error\n");    }    else if (feof(pf))    {        printf("end of file\n");    }    fclose(pf);    pf = NULL;}

打印的结果是abcdefend of file

🔍 ×