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

我的地盘我做主
该用户从未签到
 |
< >、基于C的文件操作
# ? W1 B9 `: k! W6 f 在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之。</P>9 j0 P1 P8 ^0 y3 V
< >一、流式文件操作
1 `* d( R- D. E0 O0 H ` 这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下:</P>
, }& h" ?; \7 X- a$ B! C( f- j< >typedef struct {
! v: [1 R/ h6 A, U2 [# ]int level; /* fill/empty level of buffer */
" Y% W$ P# [, g1 J& ]' C Sunsigned flags; /* File status flags */& C5 b4 i i2 M2 V) ~4 N
char fd; /* File descriptor */
" Z) s( j' s. k& u, Zunsigned char hold; /* Ungetc char if no buffer */% O6 _' N* S4 g: O
int bsize; /* Buffer size */* k7 v; o. i/ o3 H/ v
unsigned char _FAR *buffer; /* Data transfer buffer */
) L7 j( I6 G" v1 \$ Dunsigned char _FAR *curp; /* Current active pointer */
; R* j$ N/ l J2 k( \0 f9 g: cunsigned istemp; /* Temporary file indicator */6 h' Q; R1 s# H0 ~
short token; /* Used for validity checking */
; q& f3 z6 ?0 |. ^$ K# f} FILE; /* This is the FILE object */</P>
( N k, ]) r9 r$ q3 p: Z< > FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行,此种文件操作常用的函数见下表 函数 功能
; D* E' w/ T" M, qfopen() 打开流 2 o. Z$ x2 e; G, x
fclose() 关闭流 , g5 L' {4 i/ t0 i/ z- ]0 H: l
fputc() 写一个字符到流中 % c; {% c- V _) C. {- m
fgetc() 从流中读一个字符
K4 q% y' [7 z m" Ufseek() 在流中定位到指定的字符 # V/ O; t* z, j: G9 R
fputs() 写字符串到流
7 ?: ~* G( v, W9 ?, \2 x) hfgets() 从流中读一行或指定个字符 ) I/ x u8 N* w* _ X3 T
fprintf() 按格式输出到流
( x3 W; i4 ^* u7 k8 z8 }5 k0 Pfscanf() 从流中按格式读取
! V J$ _1 N4 P8 F- G8 R* Tfeof() 到达文件尾时返回真值 R; F" A' ]& y* B6 I
ferror() 发生错误时返回其值 - F. j( G6 p" ^3 Q+ u0 |
rewind() 复位文件定位器到文件开始处 ( s$ ~& _$ A8 \+ m& ~# u0 p. |. c
remove() 删除文件
3 r% O1 ]* P" Ffread() 从流中读指定个数的字符 4 \# d3 G! A2 U4 k. r) e( i; m
fwrite() 向流中写指定个数的字符
; ~8 E0 v7 W6 B$ b# P6 U; v1 Qtmpfile() 生成一个临时文件流
; h. L( v6 n9 u2 @tmpnam() 生成一个唯一的文件名 </P>) z! H& N& g' |5 g2 i
< >+ J& I9 W! J- N8 z/ y, {4 H0 t* L
下面就介绍一下这些函数</P>
7 @ n3 u( C: h6 z z6 w7 | J< >1.fopen()
, k) x \8 y$ Y4 r2 [6 H( V9 u fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能</P>
* K! Y+ L- o! U* V$ ^. a< >为使用而打开一个流
* R3 x/ d; M2 C3 T9 Z: t把一个文件和此流相连接
% e) m( x' |" X/ f给此流返回一个FILR指针
# T0 V j3 W3 | A4 a参数filename指向要打开的文件名,mode表示打开状态的字符串,其取值如下表</P>
4 J( |; e! u; q& t< >字符串 含义
) v9 S2 w9 ^2 l" {: I6 |"r" 以只读方式打开文件 , _( N7 Z6 n( E6 q- B! W* F
"w" 以只写方式打开文件
8 S e; Q/ b/ |# X7 Q0 h/ j8 q. b8 g"a" 以追加方式打开文件 " f! y" `9 X" X
"r+" 以读/写方式打开文件,如无文件出错
; _# p* C: `3 f* a"w+" 以读/写方式打开文件,如无文件生成新文件 </P>6 c- C4 E3 i8 S1 i2 w% W3 S
< > 一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符'\n',而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。</P>
# M% a5 J/ K2 b# h# ?" [; {< > 系统默认的是以文本模式打开,可以修改全部变量_fmode的值来修改这个设置,例如_fmode=O_TEXT;就设置默认打开方式为文本模式;而_fmode=O_BINARY;则设置默认打开方式是二进制模式。</P>: N) e! ?6 z& F
< > 我们也可以在模式字符串中指定打开的模式,如"rb"表示以二进制模式打开只读文件,"w+t"或"wt+"表示以文本模式打开读/写文件。</P>1 J: f& y3 J- M1 Z4 r2 {
< > 此函数返回一个FILE指针,所以申明一个FILE指针后不用初始化,而是用fopen()来返回一个指针并与一个特定的文件相连,如果成败,返回NULL。</P>4 }0 f, j. D2 l' ~
< >例:</P>
+ F% n$ Q! \; p" U7 u9 y< > FILE *fp; ; ?; D) `( I5 W& p- m% d. [
if(fp=fopen("123.456","wb"))
0 l% i9 A2 ~; z8 P7 i/ f puts("打开文件成功");) r) N, j9 Q: j. C- O
else {7 L- n. w- c
puts("打开文件成败"); </P>& `# D5 T" m9 a; f+ u3 U7 H0 I
< >2.fclose() ) Z4 o3 a( \# Z- v! S) z1 ^9 I
fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。</P>
4 x e/ r1 d) ~< > 在程序结束时一定要记得关闭打开的文件,不然可能会造成数据丢失的情况,我以前就经常犯这样的毛病。</P>" G1 D* P, _( d1 L) |; _
< >例:fclose(fp);</P>
2 z' C/ w2 b& ?; H# Q6 R; w< >3.fputc()0 U6 ]; y! p. s, x* \) v0 F
向流写一个字符,原型是int fputc(int c, FILE *stream); 成功返回这个字符,失败返回EOF。</P>/ l, ]9 _( p7 s5 g
< >例:fputc('X',fp);</P>% [ ]/ z% P# z; B
< >4.fgetc()
' }8 V' d0 X5 h* d8 @+ u* o 从流中读一个字符,原型是int fputc(FILE *stream); 成功返回这个字符,失败返回EOF。</P>
5 Y% R, v& f: M0 N% j< >例:char ch1=fgetc(fp);</P>5 H d$ u# O! G! m: X; |
< >5. fseek()( o0 C" G( C6 m' N
此函数一般用于二进制模式打开的文件中,功能是定位到流中指定的位置,原型是int fseek(FILE *stream, long offset, int whence);如果成功返回0,参数offset是移动的字符数,whence是移动的基准,取值是</P>
$ K1 M% c3 F+ Q: ]< >符号常量 值 基准位置
T) Q0 _5 g# Y N& U5 USEEK_SET 0 文件开头
, j8 `# e6 P4 h3 `6 G/ L4 ASEEK_CUR 1 当前读写的位置 / m. Q( K# D( X1 _6 n- R
SEEK_END 2 文件尾部 </P>( }$ g# U# S, ~( d
< >例:fseek(fp,1234L,SEEK_CUR);//把读写位置从当前位置向后移动1234字节(L后缀表示长整数)</P>
2 h" v7 W) y( S Q* p< > fseek(fp,0L,2);//把读写位置移动到文件尾</P>6 Q8 S8 t2 R V
< >6.fputs()9 l8 m4 k, Q/ u- O! e- N
写一个字符串到流中,原型int fputs(const char *s, FILE *stream); </P>/ P. M7 ?: K2 J
< >例:fputs("I Love You",fp);</P>( P8 D$ V& F7 J
< >7.fgets()
, k8 @7 a2 f- t4 q 从流中读一行或指定个字符,原型是char *fgets(char *s, int n, FILE *stream); 从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s的指针,否则返回NULL。</P>
% c9 b# v7 Z6 s< >例:如果一个文件的当前位置的文本如下</P>/ z$ m2 D6 w8 R* [4 N9 ^+ M
< >Love ,I Have</P>
+ u4 X" f+ J- n; X$ n<P>But ........</P>; ?$ z! x1 D4 D I2 \; U) T {
<P>如果用</P>& o/ ^* U* N7 t) g
<P> fgets(str1,4,file1);</P>( Y q5 j. S/ L! E
<P>则执行后str1="Lov",读取了4-1=3个字符,而如果用</P>& E* w, C$ n5 S0 m& J" c( t
<P> fgets(str1,23,file1);</P>! M8 h6 z8 V& ~8 {
<P>则执行str="Love ,I Have",读取了一行(不包括行尾的'\n')。</P>
7 H8 x8 L7 g1 f8 u) K, d% A<P>8.fprintf()
4 j; | Y3 D- Q* M; h. _5 t1 { 按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了</P> V U4 A% v/ [) n9 M
<P>例:fprintf(fp,"%2d%s",4,"Hahaha");</P>8 C0 \+ f% b% {3 }
<P>9.fscanf()& g1 e$ N. U! j+ v
从流中按格式读取,其原型是int fscanf(FILE *stream, const char *format[, address, ...]);其用法和scanf()相同,不过不是从控制台读取,而是从流读取罢了。</P>4 t2 h; B4 s; H0 A: i! X! _
<P>例:fscanf(fp,"%d%d" ,&x,&y);</P>
5 n2 n# R$ t+ h$ b5 L<P>10.feof()& v# `- l; J5 z* v; g
检测是否已到文件尾,是返回真,否则返回0,其原型是int feof(FILE *stream);</P>4 f) v1 W4 e4 ^- C6 O5 }, Z
<P>例:if(feof(fp))printf("已到文件尾");</P>
; h% b( u7 {( X& e, L- T% O<P>11.ferror()
0 m' J4 e2 f! ^- w, u; n) f b1 `; y/ m 原型是int ferror(FILE *stream);返回流最近的错误代码,可用clearerr()来清除它,clearerr()的原型是void clearerr(FILE *stream);</P>
% L! O+ ?2 B. U<P>例:printf("%d",ferror(fp));</P>* ]6 H" y+ i: t+ ]7 r+ R
<P>12.rewind()& x% A( r/ g* X% P7 A. s
把当前的读写位置回到文件开始,原型是void rewind(FILE *stream);其实本函数相当于fseek(fp,0L,SEEK_SET);</P>
8 I* ^& t" D+ r2 ]8 J8 }1 s<P>例:rewind(fp);</P>1 ?. I- K% G% V5 M) |. V
<P>12.remove()/ i+ y5 b q$ i% B, K3 u. E
删除文件,原型是int remove(const char *filename); 参数就是要删除的文件名,成功返回0。</P>2 t8 J. ?/ s2 b5 n! e
<P>例:remove("c:\\io.sys");</P>
; ]3 B- O( L7 K) r$ g: X& \<P>13.fread()
) N) X" i# ^7 f: F$ I0 h 从流中读指定个数的字符,原型是size_t fread(void *ptr, size_t size, size_t n, FILE *stream);参数ptr是保存读取的数据,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是读取的块数,如果成功,返回实际读取的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>2 S' i3 F4 j& A1 H# b, R6 U
<P>例:</P> B5 \) ]5 R, a8 g
<P> char x[4230];
- D* v# x# X1 I( f7 X4 L& b3 J FILE *file1=fopen("c:\\msdos.sys","r");
7 d) w* Q1 N2 B+ K$ I5 l: `8 l fread(x,200,12 ,file1);//共读取200*12=2400个字节</P>& x6 q: G. _4 ^; R
<P>14.fwrite()/ d& g4 j& C5 q- P
与fread对应,向流中写指定的数据,原型是size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);参数ptr是要写入的数据指针,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是要写的块数,如果成功,返回实际写入的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>
- N4 ~" N r* k4 a% X! l' K! r<P>例:</P>5 K$ `3 l$ Z9 S* a6 q
<P> char x[]="I Love You";5 _3 b" B3 \% [# \* Y/ ^1 ?
fwire(x, 6,12,fp);//写入6*12=72字节</P>3 O" j0 D& _" W
<P> 将把"I Love"写到流fp中12次,共72字节</P>- d' X; i. ]5 \0 ?7 U( L
<P>15.tmpfile()
0 ]: k0 g; y& C) z4 G 其原型是FILE *tmpfile(void); 生成一个临时文件,以"w+b"的模式打开,并返回这个临时流的指针,如果失败返回NULL。在程序结束时,这个文件会被自动删除。</P>
( [' h9 |9 P$ n0 y: h* C( `+ x( d& d<P>例:FILE *fp=tmpfile();</P>7 \0 C/ ~! H( h8 G0 h5 B+ A
<P>16.tmpnam();
3 m; {. z- ], `7 u 其原型为char *tmpnam(char *s); 生成一个唯一的文件名,其实tmpfile()就调用了此函数,参数s用来保存得到的文件名,并返回这个指针,如果失败,返回NULL。</P>8 i! T% k8 k; H+ A; \: G! e4 V u1 O
+ i" {4 u6 d5 ]
<P>
- V$ j' Y7 U2 U. |; y n) ~: V; { </P> |
zan
|