- 在线时间
- 0 小时
- 最后登录
- 2007-9-23
- 注册时间
- 2004-9-10
- 听众数
- 3
- 收听数
- 0
- 能力
- 0 分
- 体力
- 9975 点
- 威望
- 7 点
- 阅读权限
- 150
- 积分
- 4048
- 相册
- 0
- 日志
- 0
- 记录
- 0
- 帖子
- 1893
- 主题
- 823
- 精华
- 2
- 分享
- 0
- 好友
- 0

我的地盘我做主
该用户从未签到
 |
< >、基于C的文件操作 5 g/ Z6 y) H% W4 G" T
在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之。</P>
2 C( k4 m1 W, J5 a. f< >一、流式文件操作
, M- S7 g) a- e 这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下:</P>9 C5 w/ l l* g! J. ~6 ~( \( l
< >typedef struct {) p$ ~4 Y5 f; N1 t0 R! v5 H0 ?% L4 O
int level; /* fill/empty level of buffer */7 m/ B+ _' H' O) Z
unsigned flags; /* File status flags */
4 c8 R/ d, C1 H! zchar fd; /* File descriptor */$ U* s x$ \4 A: ?
unsigned char hold; /* Ungetc char if no buffer */
+ v# A2 ^+ ?7 D& k) y5 @6 [int bsize; /* Buffer size */$ a" O+ J% v# K3 |! W
unsigned char _FAR *buffer; /* Data transfer buffer */
% w# @0 I a8 k0 Junsigned char _FAR *curp; /* Current active pointer */: v7 [) C$ U8 k; B4 g9 `
unsigned istemp; /* Temporary file indicator */
/ g! K2 F ?) P# m3 |! R' wshort token; /* Used for validity checking */2 I! `7 M# h6 \3 H1 X
} FILE; /* This is the FILE object */</P>
: Q" W9 ?& U8 P; M3 ^ i< > FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行,此种文件操作常用的函数见下表 函数 功能
- l; v# \0 W( y. Wfopen() 打开流 1 @: v6 K. S. m8 J2 Q4 [' S
fclose() 关闭流
0 j" X+ f) B- m& r% @% \' ]fputc() 写一个字符到流中 + |' F- r7 S, _/ C5 D e) p8 T
fgetc() 从流中读一个字符 & H8 ~3 _7 o8 A# Z; ^2 A! X
fseek() 在流中定位到指定的字符 4 d6 w# b! x, Q/ G" d |
fputs() 写字符串到流 & B7 N& l1 J8 h5 t8 F. c! v% _3 `
fgets() 从流中读一行或指定个字符
7 M* g6 d) M4 |fprintf() 按格式输出到流
2 A2 N1 c I. [- {fscanf() 从流中按格式读取
6 z+ o q7 |7 t# E' Gfeof() 到达文件尾时返回真值 0 L; H1 Y# w' w: l# s
ferror() 发生错误时返回其值
* F3 t- ]9 T( Y" srewind() 复位文件定位器到文件开始处
% ]& s9 ?# `9 B, Dremove() 删除文件 y3 R* W8 Y2 _1 \( I; C$ Y
fread() 从流中读指定个数的字符 * H" D n7 a- x/ n
fwrite() 向流中写指定个数的字符
5 z5 J8 D2 v" O6 ltmpfile() 生成一个临时文件流 6 v1 P; d; G; j7 [- ~
tmpnam() 生成一个唯一的文件名 </P>5 f& Z: K% a7 r; {
< >2 {$ o8 k6 V. X& @3 M8 N' Z) [3 [
下面就介绍一下这些函数</P>
% R/ A: M. H7 @7 ]< >1.fopen()4 d2 I* a& a, `* k8 |
fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能</P>- z# P; k+ k% y" o; `
< >为使用而打开一个流 ' _, s$ V0 y* m8 O! E' _: k! T9 w" j
把一个文件和此流相连接
% q N* V* j- R: F" U" Z给此流返回一个FILR指针
6 d) r' q+ z9 b; ~$ I A4 V( ^1 [参数filename指向要打开的文件名,mode表示打开状态的字符串,其取值如下表</P>
5 ^1 [+ J; G/ U1 S- H a( j< >字符串 含义 % W1 ^3 v' |& z6 x0 ~
"r" 以只读方式打开文件
5 G; n; \* \. V% u"w" 以只写方式打开文件 * j2 `4 I9 ^5 S! Z
"a" 以追加方式打开文件 & s# q1 e1 b; o- p; R, B, m% ]
"r+" 以读/写方式打开文件,如无文件出错 * u6 |, M; Q6 `( S& |1 h8 x
"w+" 以读/写方式打开文件,如无文件生成新文件 </P>3 |- D/ @6 Y( W9 D. Y4 C' Y# |
< > 一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符'\n',而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。</P>
% O7 g2 P( z- P Q$ o, N( [8 g< > 系统默认的是以文本模式打开,可以修改全部变量_fmode的值来修改这个设置,例如_fmode=O_TEXT;就设置默认打开方式为文本模式;而_fmode=O_BINARY;则设置默认打开方式是二进制模式。</P>
9 b' }5 @& u8 {5 W6 g9 a* v$ B< > 我们也可以在模式字符串中指定打开的模式,如"rb"表示以二进制模式打开只读文件,"w+t"或"wt+"表示以文本模式打开读/写文件。</P># |% c6 R$ e2 a3 y: x8 Q( q) S
< > 此函数返回一个FILE指针,所以申明一个FILE指针后不用初始化,而是用fopen()来返回一个指针并与一个特定的文件相连,如果成败,返回NULL。</P>' s' W. f' K6 p" Z8 y
< >例:</P>
( Q& ~ S" L- H+ Y1 D< > FILE *fp;
. ^/ ^; p% K# u; J& ]- E if(fp=fopen("123.456","wb"))
- y/ c0 ^, f; F5 y puts("打开文件成功");6 l% A- _/ Z, Q' M$ y( K+ W
else , U! Q7 f( f6 W
puts("打开文件成败"); </P>
' |# p- W- ^3 Y& p' ^< >2.fclose() ! s2 X* ?! |6 f1 p7 |
fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。</P># [0 ]: Z& d, G0 M
< > 在程序结束时一定要记得关闭打开的文件,不然可能会造成数据丢失的情况,我以前就经常犯这样的毛病。</P>
, M2 w: X, U8 e< >例:fclose(fp);</P>6 E& p: h( q. \ C0 O, } ?) o
< >3.fputc()+ d3 f( [: p6 i/ @
向流写一个字符,原型是int fputc(int c, FILE *stream); 成功返回这个字符,失败返回EOF。</P>
% C" K1 M) N8 }# f7 p4 a; W< >例:fputc('X',fp);</P>
( b: m. W7 ]5 n+ c0 @/ n< >4.fgetc()
8 J8 ^" ^' C* p. ~5 F 从流中读一个字符,原型是int fputc(FILE *stream); 成功返回这个字符,失败返回EOF。</P>4 W" q9 ^$ u" @- T0 s/ V0 X
< >例:char ch1=fgetc(fp);</P>
: O2 ?" }5 H. Z6 J< >5. fseek()
]# B0 o; g0 i/ N- Q 此函数一般用于二进制模式打开的文件中,功能是定位到流中指定的位置,原型是int fseek(FILE *stream, long offset, int whence);如果成功返回0,参数offset是移动的字符数,whence是移动的基准,取值是</P>
2 J6 h5 C. {; V1 p, z0 W- W< >符号常量 值 基准位置
; {9 q/ o: C9 ?) D: M* b1 v; aSEEK_SET 0 文件开头 , R" B# D: @5 e" a
SEEK_CUR 1 当前读写的位置
$ `" D, ~: W+ r1 D0 lSEEK_END 2 文件尾部 </P>: x$ z3 K$ \1 j8 o' ]6 t
< >例:fseek(fp,1234L,SEEK_CUR);//把读写位置从当前位置向后移动1234字节(L后缀表示长整数)</P>; s! N0 a c" b4 w
< > fseek(fp,0L,2);//把读写位置移动到文件尾</P>& Q# |. M. P( _
< >6.fputs()5 _- x: U' z+ T* \* D- E$ j3 m
写一个字符串到流中,原型int fputs(const char *s, FILE *stream); </P>
$ a1 s; H4 p5 J/ d: Q+ ~2 r# v< >例:fputs("I Love You",fp);</P>
7 ?' E1 p4 ]1 Y' Z4 ]$ Q3 W3 B3 u1 @< >7.fgets()
; e4 n# U' i# O! E1 }/ ^ { 从流中读一行或指定个字符,原型是char *fgets(char *s, int n, FILE *stream); 从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s的指针,否则返回NULL。</P>+ K0 b7 ^' T4 R$ [$ G( j+ B
< >例:如果一个文件的当前位置的文本如下</P>
6 m. }; w* l" [< >Love ,I Have</P>
3 `7 n% x! ?5 ^0 u5 m1 Y<P>But ........</P>
( `. p6 F B! p: ^: e' q& w<P>如果用</P>4 ]3 F3 d5 r; P' A
<P> fgets(str1,4,file1);</P>
/ T; K9 T3 _3 S; j6 t; u R<P>则执行后str1="Lov",读取了4-1=3个字符,而如果用</P>
! _! i c8 q; v& {<P> fgets(str1,23,file1);</P>
- Y% P/ R3 m3 r3 W$ u! v<P>则执行str="Love ,I Have",读取了一行(不包括行尾的'\n')。</P>
5 ?6 R2 h2 s+ U- f3 X9 }& y Z3 h<P>8.fprintf()/ F1 [5 E/ v7 {7 d# V& v/ b( I
按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了</P>! a+ K0 ?) d! s; s
<P>例:fprintf(fp,"%2d%s",4,"Hahaha");</P>
: C8 {) H) a$ p' v; l<P>9.fscanf()
/ v" h! z, M6 Y' V8 A- k 从流中按格式读取,其原型是int fscanf(FILE *stream, const char *format[, address, ...]);其用法和scanf()相同,不过不是从控制台读取,而是从流读取罢了。</P>2 G* N; ]# Q8 n* O0 {- c0 f" U( b
<P>例:fscanf(fp,"%d%d" ,&x,&y);</P>. ^9 B- D& f% S0 `
<P>10.feof(); d0 n+ K4 D* P* E: v. t" ^
检测是否已到文件尾,是返回真,否则返回0,其原型是int feof(FILE *stream);</P>. c8 h, k% J9 x9 a @
<P>例:if(feof(fp))printf("已到文件尾");</P>
- ], H9 J) K8 f6 L1 A6 F<P>11.ferror()$ L0 v, K# _. x4 _( D9 K' b+ C
原型是int ferror(FILE *stream);返回流最近的错误代码,可用clearerr()来清除它,clearerr()的原型是void clearerr(FILE *stream);</P>
4 b; X, o4 b8 R3 x+ I; F<P>例:printf("%d",ferror(fp));</P>
7 D' U+ a ]" a2 ?( x<P>12.rewind()4 S6 K7 Z. s, N2 @- w6 p& w
把当前的读写位置回到文件开始,原型是void rewind(FILE *stream);其实本函数相当于fseek(fp,0L,SEEK_SET);</P>
; J; Z" `: a! S6 u* H3 F<P>例:rewind(fp);</P>: K3 A! ^4 f, d$ }6 W
<P>12.remove()# L( ~* h+ I1 J7 ^
删除文件,原型是int remove(const char *filename); 参数就是要删除的文件名,成功返回0。</P>
' ^5 Z6 Z: v0 S5 k- X<P>例:remove("c:\\io.sys");</P> K$ i* Q7 }# t+ e
<P>13.fread()- l3 k: l% E5 {8 H/ o$ g
从流中读指定个数的字符,原型是size_t fread(void *ptr, size_t size, size_t n, FILE *stream);参数ptr是保存读取的数据,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是读取的块数,如果成功,返回实际读取的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>2 @6 H8 \8 Y# D& r5 x
<P>例:</P>( ?7 D+ h& E" [% j0 `2 O
<P> char x[4230];
$ ]0 c" t- l3 u, | FILE *file1=fopen("c:\\msdos.sys","r");8 J7 F* J& m5 y# @ Z- a% Q! Q. p' q2 l
fread(x,200,12 ,file1);//共读取200*12=2400个字节</P>
* Y- B0 E' h5 E5 u- m<P>14.fwrite()
+ w# q$ Y& W( B9 g9 S 与fread对应,向流中写指定的数据,原型是size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);参数ptr是要写入的数据指针,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是要写的块数,如果成功,返回实际写入的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>( E# i" l+ L' c
<P>例:</P>
' A) I. N; a. V4 H<P> char x[]="I Love You";4 Y9 s9 K ^3 ~# Q2 v+ c) `1 v
fwire(x, 6,12,fp);//写入6*12=72字节</P>" K5 Q5 f' w$ q1 Y' K
<P> 将把"I Love"写到流fp中12次,共72字节</P>8 o6 P4 X9 w+ }+ |8 n
<P>15.tmpfile()7 p1 s* k* w1 P: {
其原型是FILE *tmpfile(void); 生成一个临时文件,以"w+b"的模式打开,并返回这个临时流的指针,如果失败返回NULL。在程序结束时,这个文件会被自动删除。</P>, X/ Q: h$ {5 I7 {) n, ]7 b
<P>例:FILE *fp=tmpfile();</P>5 L# |7 j8 c- j0 A1 r7 C4 X7 p2 ] M8 ~
<P>16.tmpnam();+ e. P+ x6 W% [( J/ v
其原型为char *tmpnam(char *s); 生成一个唯一的文件名,其实tmpfile()就调用了此函数,参数s用来保存得到的文件名,并返回这个指针,如果失败,返回NULL。</P>
9 @) k! t% p/ Z1 X( q/ j6 m( l0 v0 r( R1 V, M0 \
<P>
& B9 U; Q2 W& y5 u) ^' G0 M; \; B </P> |
zan
|