c语言对指针按字节移动,嵌入式C语言教程 C文件处理

标准C文件处理

Andrew Huang

开发中文件的重要情况不要多说。几乎所有实用程序用的带文件处理。比如制图软件就是对图片文件处理,游戏的几乎所有数据都由文件处理。

文件处理有两类,一类文本,内容是,另一类是二进制文件,两者在存储的本质上一样的,只是在程序处理有细微的差别。

每个操作系统都自己处理文件的专用的API,但是标准C制定一套标准文件处理接口,方便易用。只要是对普能文件操作,我要求学生一定要用标准C文件处理接口来处理文件。

标准C的处理,缓冲式处理文件:

一.操作文件要点:

-------------------------------------

在标准C文件处理函数中,所有打开的文件都由一个名为FILE 结构来描述.

缓冲文件系统为每个正使用的文件用FILE *在内存开辟文件信息区

文件信息用系统定义的名为FILE 的结构体描述

FILE 定义在stdio.h 中

文件使用前,必要打开.文件修改后,需要关闭文件才会把内容保存在文件系统中。

文件打开 时,系统自动 建立文件结构体,并把指向它的FILE *指针返回来,程序通过这个指针获得 文件信息,

文件关闭 后,它的文件结构体被释放.如果没有关闭,在退出程序时,操作系统会自动关闭打开文件。

文件使用方式:打开文件-->文件读/写-->关闭文件

文件的打开与关闭    C 文件操作用库函数 实现, 包含在stdio.h

打开文件fopen

函数原型: FILE    *fopen(char  *name,char *mode)

功能:按指定方式打开文件

返值:正常打开,为指向文件结构体的指针;打开失败,为 NULL

name是文件路径名,可以是绝对路径和相对路径,我建议用相对路径,并且用/来分隔,这样可以保证路径在各个操作系统的移植性.

mode是用来描述这个文件在随后如何操作的模式。它是一个字符串,可以做如下取值.

"r" 只读文件,

"w" 可读可写文件,如果文件不存在,将会自动创建,如果存在,则会被清空内容

"a" 可读可写文件,如果文件不存在,将会自动创建,如果存在,则读写指针指向文件尾。

"r+"表示打开只读文件,而且文件必须存在

"w+" 等同于"w"

"a+" 等同于"a"

b表示打开一个二进制文件,但现在已经不是必须的。(即有不有一个样),但为了有良好的风格,在打开一个二进制文件还是加上b

比如 "rb+","wb"

文件关闭fclose

作用: 使文件指针变量与文件脱钩 ,释放文件结构体和文件指针

函数原型:int  fclose(FILE  *fp)//  文件打开时返回的文件类型指针

功能:关闭fp指向的文件

返值:正常关闭为0;出错时,非0

三个特殊的文件

l   每个程序运行后, 三个特殊文件会被自动打开, 分别是标准输出, 标准输入和标准错

误输出  ,它不需要用fopen来打开即可直接使用

l   三个FILE * 全局变量在stdio.h 被声明. 因此程序只要包含stdio.h, 可以不需要打

开直接使用这个三个文件结构描述符

–   分别是 stdout,stdin,stderr.

–   可以用文件处理函数对stdout,stderr 进行写入, 相当于向屏幕打印字符.

–   可以用文件处理函数对stdin 进行读入, 相当接收键盘输入

–   即出程序时, 也不需要关闭这个三个FILE *  结构

比如我们习惯的

fprintf(stderr,"this is a error message\n");

文件打开和关闭的框架

要点,一定要对fopen结果做NULL检测!,文件打开失败的情况太多了

#define PRINT_INTX(e) printf("%s=0x%X\n",#e,e)

#define PRINT_INT(e) printf("%s=%d\n",#e,e)

void test1()

{

FILE * fp = NULL;

fp = fopen("test.txt","w+");

if(fp == NULL)

{

fprintf(stderr,"open file failure,errno=%d\n",errno);

return ;

}

PRINT_INTX(fp);

fclose(fp); //关闭文件

}

注意一个常见的错误,这个是操作符优先级=高于==,下面的表达式

if(fp  = fopen("test22.txt","w+") == NULL)

实际是

if((fp  = fopen("test22.txt","w+")) == NULL).

正确的写法是

if((fp  = fopen("test22.txt","w+")) == NULL)

void test2()

{

FILE * fp = NULL;// if(fp = fopen("test22.txt","w+") == NULL) 等于 if(fp = (fopen("test22.txt","w") == NULL))

if((fp = fopen("test22.txt","w+")) == NULL)

{

fprintf(stderr,"open file failure,errno=%d\n",errno);

return ;

}

PRINT_INTX(fp);

fclose(fp);

}

二.文件读写操作

-------------------------------------------------------------

文件读写有一个隐念的概念, 文件位置指针----- 指向当前读写位置的指针 ,它保存在内存当中。当用w,r打开文件时,指针会指向文件开始,用a模式打开,会指向文件结束

文件读写可以字符或字符串,二进制buffer等来读写,每次读写成功后,内核会把读写指针自动移到下一个位置下。

按字符来读写fputc/fgetc

–字符I/O:fputc与fgetc

lfputc

–函数原型 :intfputc(int c, FILE *fp)

–功能:把一字节代码c写入fp指向的文件中

–返值:正常,返回c;出错,为EOF

lfgetc

–函数原型:intfgetc(FILE *fp)

–功能:从fp指向的文件中读取一字节代码

返值:正常,返回读到的代码值;读到文件尾或出错,为EOF

EOF是一个整数常量,值为-1,

注意这里是用int来存取字符,这个值保存是字符的ASCII码值。

void test3()

{

FILE * fp = NULL;//char * p = malloc(10);

fp = fopen("test.txt","w+");

if(fp == NULL)

{

fprintf(stderr,"open file failure,errno=%d\n",errno);

return ;

}

fputc('A',fp);

fputc('B',fp);

fputc('C',fp);

fputc('\n',fp);

fputs("hello!\n",fp);

fputs("hi!\n",fp);

fclose(fp);

}

思考,一个文件打开两次会有情况发生?这是初学常见的问题,参考这个代码

#include

int twice_open(char * file_name)

{

FILE * src_fp = NULL,*dst_fp = NULL;

char buffer[16];

int len;

src_fp = fopen(file_name,"w+");

if(src_fp == NULL)

{

fprintf(stderr,"open file %s failure \n",file_name);

return -1;

}

//以只读的方式打开一个文本文件

dst_fp = fopen(file_name,"w");

if(dst_fp == NULL)

{

fprintf(stderr,"create destion file %s failure \n",file_name);

return -1;

}

fputs("0123456789",src_fp);

fputs("abc",dst_fp);

fclose(dst_fp);

fclose(src_fp);

return 0;

}

void test1()

{

twice_open("4.txt");

}

int main()

{

test1();

}

结果就是内容互相覆盖。fputs(将一指定的字符串写入文件内)

int fputs(const char * s,FILE * stream);

fputs()用来将参数s所指的字符串写入到参数stream所指的文件内。

返回值 若成功则返回写出的字符个数,返回EOF则表示有错误发生。

fgets(由文件中读取一字符串)

char * fgets(char * s,int size,FILE * stream);

fgets()用来从参数stream所指的文件内读入字符并存到参数s所指的内存空间,直到出现换行字符、读到文件尾或是已读了size-1个字符为止,最后会加上NULL作为字符串结束。

这通常要求学生必须记住下面框架,这是使用频率最高的结构。其它程序也是防照这个框架改写

打印文本文件内容

int type_file2(char * filename)

{

FILE * fp = NULL;

char buf[1024];

fp = fopen(filename,"r");

if(fp == NULL)

{

fprintf(stderr,"open file %s failure\n",filename);

return -1;

}

while(fgets(buf,sizeof(buf),fp) != NULL)

{

//putchar(ch);

printf(buf);

}

fclose(fp);

}

注意常见的问题,

feof是检查文件流是否读到了文件尾

int feof(FILE * stream);

feof()用来侦测是否读取到了文件尾,尾数stream为fopen()所返回之文件指针。如果已到文件尾则返回非零值,其他情况返回0。但是在读写框架使用feof往往出错。在实际编程是用不上feof的,因此我要求学员不要使用这个函数。

下面就是因为使用feof产生错误的实例。忘掉它吧,没有什么功能是必须使用feof的

/* ch12_2.c*/

/* Program to create backup of a file */

#include

main()

{

FILE *in, *out;

char ch,infile[10],outfile[10];

printf("Please enter the infile name:\n");

scanf("%s",infile);

printf("Please enter the outfile name:\n");

scanf("%s",outfile);

if ((in = fopen(infile, "r"))== NULL)

{

printf("Cannot open infile.\n");

exit(0);

}

if ((out = fopen(outfile, "w"))== NULL)

{

printf("Cannot open outfile.\n");

exit(0);

}

while (!feof(in)) //这将造成多写一字符到目标文件

fputc(fgetc(in), out);

fclose(in);

fclose(out);

}

思考,如果文本文件一行数据超过过fgets给的buffer的长度,会有什么后果?

请写程序测试一下

fgets应用实例:安全从键盘输入字符串的代码

void test7()

{

char buffer[128];

fputs("input a number:",stdout);

fgets(buffer,sizeof(buffer),stdin);//

printf("your input number %d\n",atoi(buffer));// snprintf(buffer,sizeof(buffer),"%d",100);

}

二进制数据读写

l函数原型:

size_tfread(void*buffer,size_tsize, size_tcount,FILE*fp)

size_tfwrite(void*buffer,size_tsize, size_tcount,FILE*fp)

l功能:读/写数据块

l返值:成功,返回读/写的块数;出错或文件尾,返回0

l说明:

Øtypedefunsignedsize_t;

Øbuffer:指向要输入/输出数据块的首地址的指针

Øsize:每个要读/写的数据块的大小(字节数)

Øcount:要读/写的数据块的个数

Øfp:要读/写的文件指针

Øfread与fwrite一般用于二进制文件的输入/输出

注意这里参数有两个特别的地方,FILE * 位于最后位置,读写的缓冲区的的大小是两个参数.size和count.

把读写总尺寸分成size和count,主要是方便struct 连续读写

每次读/写的总尺寸是size*count,如果成功,返回是块数

读写测试样例:读写连续结构样例

从键盘输入4个学生数据,把他们转存到磁盘文件中去

#include

#define SIZE 2

struct student_type

{ char name[10];

int num;

int age;

char addr[15];

}stud[SIZE];

void save();

void display();

int main()

{

int i;

for(i=0;i

scanf("%s%d%d%s",stud[i].name,&stud[i].num,

&stud[i].age,stud[i].addr);

save();

display();

}

void save()

{ FILE *fp;

int i;

if((fp=fopen("d:\\fengyi\\exe\\stu_dat","wb"))==NULL)

{ printf("cannot open file\n");

return;

}

for(i=0;i

if(fwrite(&stud[i],sizeof(struct student_type),1,fp)!=1)

printf("file write error\n");

fclose(fp);

}

void display()

{ FILE *fp;

int i;

if((fp=fopen("d:\\fengyi\\exe\\stu_dat","rb"))==NULL)

{ printf("cannot open file\n");

return;

}

for(i=0;i

{ fread(&stud[i],sizeof(struct student_type),1,fp);

printf("%-10s %4d %4d %-15s\n",stud[i].name,

stud[i].num,stud[i].age,stud[i].addr);

}

fclose(fp);

}

l对于一个文件读入,读入数据不足一个块算一个块.因此很容易发生下列错误

#include

main()

{ FILE * file;

char buffer[512];

file = fopen(“example.ini”,”r”);

while(fread(buffer,sizeof(buffer),1,file)>0) //无法判断最后一块的尺寸

//while(fread(buffer,1,sizeof(buffer),file)>0) //正确.

{

...

}

fclose(file);

}

正确代码是把size设为1,

fread/fwrite样例:文件拷贝

#include

int copy_file(const char * src_name,const char * dst_name)

{

FILE * src = NULL,* dst = NULL;

char buffer[1024];

int len,cnt = 0;

if((src = fopen(src_name,"rb")) == NULL)

{

fprintf(stderr,"open source file %s failure\n",src_name);

return -1;

}

if((dst = fopen(dst_name,"wb+")) == NULL)

{

fclose(src);

fprintf(stderr,"create destion file %s failure\n",dst_name);

return -2;

}

#if 1

while((len = fread(buffer,1,sizeof(buffer),src))>0)

{

cnt+= len;

fwrite(buffer,1,len,dst);

}

#endif

#if 0

//注意这样写是错误写法,这样造成最一段数据尺寸有错

while((len = fread(buffer,sizeof(buffer),1,src))>0)

{

cnt+= len;

fwrite(buffer,sizeof(buffer),len,dst);

}

#endif

fclose(dst);

fclose(src);

printf("copy file %s to %s success,bytes is %d\n",src_name,dst_name,cnt);

return 0;

}

int main()

{

copy_file("1.pdf","11.pdf");

}

fflush: 不关闭文件时保存文件

l   一般情况下只要关闭文件, 就可以把内存内容保存文件中.

l   但很多情况下是不能关闭文件的, 如服务器的日志文件, 但可以需要定时保存以防断

电丢失数据.

l  fflush  就是无需关闭文件, 强制更新文件.

int fflush(FILE* stream);

格式化I/O:fprintf与fscanf

*函数原型:

intfprintf(FILE*fp,const char*format[,argument,…])

intfscanf(FILE*fp,const char*format[,address,…])

*功能:按格式对文件进行I/O操作

*返值:成功,返回I/O的个数;出错或文件尾,返回EOF

文件的定位:rewind()

–几个概念

l文件位置指针-----指向当前读写位置的指针

l读写方式

–顺序读写:位置指针按字节位置顺序移动,叫~

–随机读写:位置指针按需要移动到任意位置,叫~

文件的定位:fseek

–fseek函数

l函数原型:intfseek(FILE*fp,longoffset,int whence)

l功能:改变文件位置指针的位置

l返值:成功,返回0 ;失败,返回非0 值

offset取值

位移量(以起始点为基点,移动的字节数)

>0向后移动

<0向前移动

whence

起始点

文件开始SEEK_SET0

文件当前位置SEEK_CUR1

文件末尾SEEK_END2

样例:1)欲将读写位置移动到文件开头时:fseek(FILE *stream,0,SEEK_SET);

2)欲将读写位置移动到文件尾时:fseek(FILE *stream,0,0SEEK_END);

lftell函数

–函数原型:longftell(FILE*fp)

–功能:返回位置指针当前位置(用相对文件开头的位移量表示)

–返值:成功,返回当前位置指针位置;失败,返回-1L,

一种求文件大小尺寸代码

long file_size(char * filename)

{

FILE * fp = NULL;

long len;

fp = fopen(filename,"rb");

if(fp == NULL)

return -1;

if(fseek(fp,0,SEEK_END)== -1)

return -2;

len = ftell(fp);

fclose(fp);

return len;

}

void test13()

{

PRINT_INT(file_size("1.pdf"));

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值