c语言中关于文件操作的总结(笔记版)

1、含义:

存储在外存储器上,相较于常量、变量、数据等都是存储在内存储器上的。

键盘是输入文件stdin;(只读)

显示器是输出文件stdout;(只写)

写文件,我们理解为输出,从内存到外存;比如printf,fprintf,fputc,fputs,fwrite;

读文件,我们理解为输入,从外存到内存;比如scanf,fscanf,fgetc,fgets,fread;

2、分类:

1)按照存取方式:

顺序存取:读写操作总是从文件的开始位置开始;

随机存取:读写操作可以从文件的任意位置进行。

2)按照存取形式:

文本文件:每个字符都是以ASCII码值的形式存储;定长译码编码,但文件可识别。

 

二进制文件:把数据按其在内存中的存储形式(二进制码)形式存储;不定长译码编码,但文件不可识别。

例如:

3.14,文本文件,会将每个数字看做是字符存储的,一个字符占一个字节;//打开文件后,所见即所得;

若作为二进制文件存储的话,如果使用float类型,则是占4个字节,使用double则是占8个字节。//打开文件后,是乱码;

但如果文本文件和二进制文件都存储的是字符数组的内容的话,打开二进制文件,看到的是对应的十六进制数。

3、文件指针

#include <stdio.h>

typedef struct{
    short level; //缓冲区满或空 程度
    unsigned flags;//文件状态标志
    char fd; //文件描述符
    unsigned char hold;// 如无缓冲区不读取字符
    char filename[20];//文件名
    char path[30];//文件路径
}FILE;

 FILE* fp;

4、打开文件

对文件进行读写操作前,需要打开文件:

注意在linux系统下,mode中加b与不加b是一样的。例如,r和rb是一样的。以下是在windows平台下的区别,在linux下,我们如果添加b,只是为了以后方便移植到windows平台。

FILE* fp = fopen(文件名,文件的打开方式);

例如:
FILE* fp = fopen("test.txt","r");
FILE* fp = fopen("\\nand_flash\\test.txt","r");\\用两个/表示一个\

若文件无法打开,会返回NULL。
故:
FILE* fp;
if((fp = fopen("test.txt","r"))==NULL)
{
    printf("fopen file fail\n");
    exit;
}

打开方式含义打开方式含义
“r”只读,打开文本文件,文件必须存在“r+”可读写,打开文本文件,文件必须存在
“w”只写,打开文本文件,文件不必存在,若存在,fopen的时候内容会被清除“w+”可读写,建立并打开新的文本文件,文件可以不存在,如果存在,fopen的时候内容会被清除
“a”追加写,文件可以不存在,从文本文件尾开始添加“a+”可读写,打开文本文件,文件可以不存在,在文件末尾添加
"rb"只读,打开二进制文件,文件必须存在"rb+"读写,打开二进制文件,文件必须存在
“wb”只写,打开二进制文件,文件不必存在,若存在,内容会被清除“wb+”读写,建立并打开新的二进制文件,文件可以不存在,如果存在,内容会被清除
"ab"追加,文件可以不存在,从二进制文件尾开始添加"ab+"读写,打开二进制文件,文件可以不存在,在文件末尾添加

r与r+比较:二者都需要先建立文件;r+增加了可写的功能,即:打开一次文件,可以写文件,读文件;写的时候是在文件位置指针的位置写的,会覆盖指针后面的内容。写几个字节覆盖几个字节。

      r+的写优势:1)文件位置指针在第一个数据前,不会清除原文件的所有内容,通过fseek()函数来改变文件位置指针来写内容(写几个,覆盖几个)。2)读写文件时,只需要打开一次文件即可。

w与w+比较:二者对文件的存在都没有要求,如果文件存在,fopen的时候,原文件被删除,重新创立了新的文件;w+增加了读功能,即:写入文件后,文件位置指针在最后一个数据后,通过fseek来更改文件位置指针,还可以将文件的内容读出来,

      注意,w+是无法先读后写,因为,使用fopen后,就是一个空的文件。

r与w的比较:r文件必须要存在;w文件可存在,可不存在,如果存在,原文件中的内容会被覆盖(fopen的时候,原文件被删除,重新生成了一个同名的文件),如果不存在,会建立这个文件。

      w的优势,重新生成一个新的文件,并且会覆盖原文件。

r+与w+的比较:二者都既能读又能写;r+要求文件存在,w+不要求文件存在,若存在,则会删除重新创建新的文件(即使用w+属性,无论文件存不存在,都会重新创建);

r+可以先写后读,也可以先读后写(因为文件已存在,且其中有内容),w+只能先写后读,因为fopen之后,文件为新建的文件为空,故只能先写后读。

w与a的比较:二者都不要求文件是否存在;w无论文件存在与否,都会删除文件,新建文件;a的话,如果文件未创建的话,与w一样,如果文件创建的话,则会在文件末尾续写内容

a与a+的比较:二者都不要求文件是否存在,都不能改变文件的原内容;a只能在末尾添加,文件位置指针无效(即fseek无效)即:只能在文件末尾写,不能读;

a+只能在结尾追加写, 文件位置指针只对读有效, (追加写操作会将文件指针移动到文件尾),即只要追加写操作会将文件位置指针挪动到最后一个数据后,而无论前面是否使用了fseek。

但是当第一次读文件时,文件指针是在第一个数据前的。写操作执行后,指针就在最后一个数据之后了。(可以这么理解,文件打开后,默认的位置指针都是在第一个字符前,但是如果此时要写入数据的话,会同时跟着一个fseek(fp,0L,SEEK_END);操作,所以,只要是追加写之后,如果要读字符的话,就必须首先挪动文件位置指针。

小结:打开文件后的第一次读操作都是从文件第一个数据前开始的,无论是r,r+,a+(w+第一个是空文件,没法读取);

w、w+、肯定是在起始位置写入;a、a+只能在末尾写。

5、关闭文件 

对文件读写完成后,应该关闭,防止丢失数据;

关闭文件的实质,是释放文件指针,使文件指针变量不再指向该文件。

fclose(fp);
//关闭成功返回0;
//关闭失败返回非0

6、文件的读写

6.1 fscanf 和fprintf //读写文本文件,数据格式任意

记忆:fscanf与fprintf 与scanf 和printf的格式及含义基本上是相同的;

scanf,是键盘(stdin文件)读取一个值,并赋值给一个变量;//fscanf也是从文件中读取值,赋给某个变量

   scanf("%d",&m)等价于 fscanf(stdin,"%d",&m);

printf,是将一个变量的值,写入到显示器(stdout文件);//fprintf也是将某个变量写到文件中;

   printf("%d",n);等价于 fprintf(stdout,"%d",n);

1)fprintf(文件指针,格式字符串,输出项表)
例如:
fprintf(fp,"%d",m);//将变量m以%d的形式写到fp指向的文件中

2)fscanf(文件指针,格式字符串,输入项表)
例如:
fscanf(fp,"%d",&n);//注意取地址符号&//将fp所指的文件以%d的形式读取到变量n中

6.2 fputc(putc)和fgetc(getc)//从文本文件中读写字符

fputc(ch,fp);//ch可以是字符常量,可以是字符变量,写入到fp所指的文件中
putchar(ch);等价于fputc(ch,stdout);

ch = fgetc(fp);//从fp所指的文件中读取字符作为返回值赋给字符型变量ch
ch = getchar();等价于ch = getc(stdin);

6.3 fputs和fgets函数// 从文本文件中读写字符

fputs(str,fp);//str是待写入文件的字符串的首地址
//注意:字符串最后的\0不会写入文件,也不会自动加'\n';
写入成功,函数值为非0,否则为0;

fgets(str,n,fp);//str是存放字符串的起始地址;n是int型变量
//从fp所指的文件中读n-1个字符依次放入到以str为旗帜地址的内存中,读入结束后,自动在最后加'\n',并以str作为函数值返回。
//注意:调用该函数时,最多只能读取n-1个字符。要为'\0'保留一个字符的空间

 6.4 fwrite和fread//二进制文件中读写数据

fwrite(buffer,size,count,fp);
//buffer为指针,代表内存中一段存储空间的首地址;
size,代表每单元的字节数;
count代表要进行读写的单元数
//将以buffer为其实地址的内存中的count个单元,每个单元size个字节写到fp所指的文件中。

int a[4]={1,2,3,4}; fwrite(a,2,4,fp);
//将以a为起始地址的内存中的4个单元,每单元2个字节写(输出)到fp所指的文件中。

fread(buffer,size,count,fp);
//buffer是指针,代表内存中存储空间的地址;
count代表进行读写的单元数;
size带包每单元的字节数;
//从fp所指的文件中读(输入)count个单元,每个单元size个字节,到以buffer为起始地址的内存中。

int  a[4];
fread(a,2,4,fp);
//从fp所指的we年中读4个单元,每个单元2个字节,到以a为起始地址的内存中。

经过测试,当使用文本形式打开文件的时候,写入文件的内容均为字符串,此时使用fwrite、fread函数也能 正常读写文件。可以参考本文

    fopne("1.dat","w");
    char temp[1024];
    sprintf(temp,"mm=%d;\r\n",mm);
    fwrite(temp,strlen(temp),1,fp);

7、判断文件是否结束

1)feof(fp); 判断文件是否结束------ f  end of file//可以判断二进制文件,也可以判断文本文件

文件结束:返回值为1;

文件没有结束,返回值为0;

2)EOF;//文本文件

因为文本文件都是ASCII码,0-255,不可能为-1,所以使用EOF作为文本文件的结束标志。

注意:fgets()函数读到'/n'就停止,而不管是否达到数目要求。同时在读取的字符串的最后加上'/0'。

fgets()函数执行完以后,返回一个指向该串的指针。如果读到文件尾或出错,则均返回一个空指针NULL,所以常用feof()函数来测定是否到了文件尾或者是ferror()函数来测试是否出错。

#include "stdio.h"

int main() {

    FILE *fp;

    char str[128];

    if((fp=fopen("test.txt", "r"))==NULL) {

        printf("cannot open file/n"); exit(1);

    }

    while(!feof(fp)) {

        if(fgets(str, 128, fp)!=NULL)

        printf("%s", str);

    }

    fclose(fp);

}

    char s[1024];
    while((fgets(s,1024,fp))!=NULL)
    {
         printf("%s",s);
    }

8、文件定位函数

文件fopen后,文件位置指针指向文件的开头,第一个数据之前;//注意是文件位置指针,不是文件指针

文件fclose后,文件位置指针指向文件末尾,最后一个数据之后。

对数据进行读操作后,文件位置指针指向尚未读数据之前,即是从指针后的数据开始读。

当数据进行写操作后,文件位置真值指向刚写入数据之后。

我们使用fseek函数实现改变文件的位置指针。

起始点名称代表数字
文件开始位置SEEK_SET0
文件当前位置SEEK_CUR1
文件末尾位置SEEK_END2

默认的就是文件开始位置,所以,SEEK_SET表示的是离文件开始位置的字节数,set 即off_set 

fseek(fp,offset,origin);//一般用于二进制文件
offset是以origin为基点,以字节为单位的位移量,当offset为正整数,表示位置指针从指定位置向后移动,当offset为负整数,表示位置指针从指定位置向前移动,为长整型。

fseek(fp,30L,SEEK_SET);//位置指针从开始位置向后移30个字节。
fseek(fp,-10*sizeof(int),SEEK_END);//位置指针从文件尾部位置向前移10*sizeof(int)个字节。

fseek(fp,0L,SEEK_SET);//位置指针移动到开始位置。
fseek(fp,0L,SEEK_END);//位置指针移动到末尾位置。

//ftell告诉你离开始的地方有多远了。。。//也可以说是当前的位置是哪?

long t = ftell(fp);
//返回当前位置指针据文件开头的字节数

//该函数可以用来获取文件的大小
fseek(fp,0L,SEEK_END);
long t = ftell(fp);

void rewind(fp);//无返回值
//使文件位置指针返回到文件开头位置,等价于 fseek(fp,0L,SEEK_SET);

9、fflush()函数

int fflush(FILE* stream);

//如果参数为NULL,会刷新所有打开的输出的流
fflush(NULL);

比如:printf("hello world"); 有时候会打印不出来。

标准输出是行缓冲模式,只有遇到换行符或者一行满了之后,才会刷新缓冲区,所以,我们会添加'\n'------》printf("hello world\n");   或者使用printf("hello world");   fflush(stdout); 

缓冲区的作用:合并系统调用;

模式:

  • 行缓冲---->换行的时候刷新或满了时候刷新或强制刷新(fflush):如stdout
  • 全缓冲---->满了时候刷新或强制刷新(fflush)--->这是默认的方式,只要不是终端设备的都是全缓冲。
  • 无缓冲---->需要立即输出的内容,如stderr.

可以通过setvbuf修改缓冲模式的相关内容(不建议修改)

10、总结

1)c语言中关于文件的操作都是以f开头的。

2)r+,w+,a+,其实都可以通过r,w,a及fseek函数多次操作实现。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值