c语言字节写入文件,C语言文件操作

所谓文件(file)一般指存储在外部介质上数据的集合,比如我们经常使用的mp3、mp4、txt、bmp、jpg、exe、rmvb等等。这些文件各有各的用途,我们通常将它们存放在磁盘或者可移动盘等介质中。那么,为什么这里面又有这么多种格式的文件呢?原因很简单,它们各有各的用途,区分就在于这些文件里面存放的数据集合所遵循的存储规则不一样。举个例子比如bmp图片文件,为什么他能够表示一张图片,因为它有固定的格式,哪一段到哪一段,哪个偏移到哪个偏移应该存放什么数据是规定好了的。比如有文件头,一般是一个结构体,存放的文件的一些信息,如图片的大小,像素等等。再后来有数据区。然后我们要显示一张图片,就只需要按照前面所说的规则将文件头结构和数据块读出来,然后将这些数据在屏幕上用颜色表示出来,就成了一张图片。其它文件格式也类似。

这里要说一个更重要的例子,对我们理解文件有好处。那么这个文件就是exe文件(这里只讨论windows平台),通常我们认为它是一个可执行程序,这无疑是增加了它的神秘度。从本质上来讲exe无非是一种固定的文件格式罢了。既然这样,它就有一套自己的存储规则。跟前面的图片文件一样有规则。此时,你可能会问:你这么说那我就可以纯手工(直接填写数据填充文件)写出一个exe可执行文件了?

面对你这个问题,我只能说你已经习惯思考了,已经习惯给自己提问了,已经很聪明了。那么答案是肯定的,你完全可以用一个编辑器直接填写数据写出一个helloworld.exe文件或者helloworld.dll文件。因为这些具有一定格式规则的文件一般是二进制存储的,于是我们可以用一个二进制编辑器新建一个二进制文件,然后向里面填写数据。然后双击运行输出“helloworld”字符串。你可能会觉得很有成就感,我之前就写过一个exe和dll。这里exe和dll的文件格式也就是著名的PE文件格式。有兴趣你可以去查阅相关资料,此非本文重点。

总结上面的认识,文件无非就是一段数据的集合,这些数据可以是有规则的集合,也可以是无序的集合。操作系统也就是以文件为单位对数据进行管理的。也就是说,要访问外部介质上的数据,必须先按照文件名进行查找,然后从该文件中读取数据。要想写数据到外部介质,必须得建立一个文件,然后再写入。因此,这样来看,你眼前的文件将是一堆一堆数据而已,也没有什么类型文件之分了,类型只是为了区分而已,假如你把一个exe文件的扩展名改为txt,把它用记事本打开,同样是可行的,只是会执行exe文件里面的东西而已。(这里又不得不提到一点,如果你是一名程序员或者爱好者,那么你不应该将你的文件扩展名给隐藏了,要让它显示出来,如果你隐藏了,无非是增加了它的神秘感,同时在文件操作上不方便。通过上面的本质,我相信你能体会到我为什么这么说。)

说到这里,你应该知道文件是什么了,那么再来看二进制文件和ASCII文本文件,为什么要分为这两种呢?

首先、文本文件方式存储多用于我们需要明显知道文件里面的内容时,比如ini、h、c等文件都是文本文件,这种文件存储的是字符(ASCII码),比如一个整数10000,类型是short,占2字节,存储文本形式将占用5个字节,一共5个字符。你可以想想更多的例子,体会文本文件方便之处(提示:这里的文本文件不是说是txt文件,而是指所有以文本格式存储的文件。)

其次、二进制文件方式多用于直接将内存里面的数据形式原封不动存放到文件里,比如上面的short

10000,在内存中占2字节,存储内容为10000的二进制数,存到文件后还是占2字节,内容也是10000的二进制。这种方式可以整块数据一块儿存储,同时还可以将内存数据映射到文件里。

由上面两点,C语言操作文件可以是字节流或者二进制流。它把数据看成是一连串字符(字节),而不需要考虑边界。C语言对文件的存取是以字节为单位的。输入输出的数据流的开始和结束仅受程序控制而不受物理符号(如回车换行符)控制。这种文件通常称为流式文件,大大增加了灵活性。我们可以产生很多自己的文件格式,在游戏程序里面,用得比较多的就是资源包的格式,一般就是自定义的存取规则。我之前也写了一个包文件,存取只需要遵循规则,原理是非常简单的。大家可以试试在脑子里面构造一个包文件。

在ANSI

C标准中,使用的是“缓冲文件系统”。所谓缓冲文件系统指系统自动地在内存区为每一个正在使用的文件名开辟一个缓冲区,从内存向磁盘输出数据必须先送到内存中的缓冲区,装满后再一起送到磁盘去。反向也是如此。这里需要说明两个词:“输入”“输出”。输入表示从文件里读数据到程序里,输出表示从程序里写数据到文件中。

了解了文件及文件存储形式,下面该正式进入文件的读写了,不要太激动,还是慢慢来。细节往往决定成败。在缓冲文件系统中,有一个很重要的一个东西就是文件指针,每个使用的文件都会在内存中开辟一个区,用于存放文件的有关信息,这些文件信息就保存在一个结构体变量中的,这个结构体是由系统定义的,名为FILE,先来看看VC2005在stdio.h下FILE结构体的定义:

a4c26d1e5885305701be709a3d33442f.png

struct_iobuf

{char *_ptr; //指向buffer中第一个未读的字节

int _cnt; //记录剩余未读字节的个数

char *_base; //指向一个字符数组,即这个文件的缓冲

int _flag; //FILE结构所代表的打开文件的一些属性

int _file; //用于获取文件描述,可以使用fileno函数获得此文件的句柄。

int _charbuf; //单字节的缓冲,即缓冲大小仅为1个字节,如果为单字节缓冲,_base将无效

int _bufsiz; //记录这个缓冲的大小

char *_tmpfname; //temporary file (i.e., one created by tmpfile()//call). delete, if necessary (don't have to on//Windows NT because it was done by the system when//the handle was closed). also, free up the heap//block holding the pathname.

};

typedefstruct _iobuf FILE;

a4c26d1e5885305701be709a3d33442f.png

好了,上面的结构体就是这样定义的。这里不得不再次提到缓冲:

缓冲模式

常量(mode)

备注

无缓冲模式

_IONBF

该文件不使用任何缓冲,也可以说是字节缓冲

只能保存一个字节。

行缓冲模式

_IOLBF

仅对文本模式打开的文件有效,所谓行,即是指每收到一个换行符(/n或/r/n),就将缓冲flush掉

全缓冲模式

_IOFBF

仅当缓冲满时才进行flush

上面结构体中的_flag就标记了缓冲的信息(我们关心这三个):

a4c26d1e5885305701be709a3d33442f.png

#define _IOYOURBUF 0x0100 //使用用户通过setbuf提供的buffer

#define _IOMYBUF 0x0008 //这个文件使用内部的缓冲

#define _IONBF 0x0004 //无缓冲模式

#define _IOLBF 0x0040 //行缓冲模式

#define _IOFBF 0x0000 //全缓冲模式

a4c26d1e5885305701be709a3d33442f.png

同时,_flag也标记了读写模式,比如"r+"、"w+"等。

#define _IOREAD 0x0001 //只读

#define _IOWRT 0x0002 //只写

#define _IORW 0x0080 //可读可写

上面的3中模式就是"r"、"w"、"+"任意组合起来表示的意思。

正因为使用缓冲模式,是为了避免频繁的系统调用开销,有了缓冲就不需要每次都访问实际的文件。当然缓冲也会带来隐患,比如写文件时,先是到缓冲,如果此时系统崩溃或者进程意外退出时,有可能导致文件数据的丢失。因此C语言提供了几个基本的函数,弥补缓冲带来的问题:

a4c26d1e5885305701be709a3d33442f.png

int fflush( FILE* stream ) //flush指定文件的缓冲,若参数为NULL,则flush所有文件的缓冲。

int setvbuf( FILE *stream, char* buf, int mode, size_t size ) //设定缓冲类型,如上面的表格。

void setbuf( FILE* stream, char* buf ) //设置文件的缓冲,等价于( void )setvbuf( stream, buf, _IOFBF, BUFSIZ ).

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值