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

我的地盘我做主
该用户从未签到
 |
< >、基于C的文件操作
" Y3 F( R* } F; @, a, C1 J$ q 在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之。</P>0 ~0 Y3 v, N# B* ]
< >一、流式文件操作' ?; P y9 L9 ~
这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下:</P>/ ~) {7 i' Q. V+ B" m( P( S: X$ l% v
< >typedef struct {( |. ^$ C+ V: m* j( s
int level; /* fill/empty level of buffer */( r) z: p; \* m9 `/ Z. r
unsigned flags; /* File status flags */7 I4 |5 x4 \1 r) o- i
char fd; /* File descriptor */9 ^( L+ B! x' J. L8 n. t
unsigned char hold; /* Ungetc char if no buffer */
, K7 o/ W0 X, {& Q2 eint bsize; /* Buffer size */
% [- U! A5 O; Y/ N* uunsigned char _FAR *buffer; /* Data transfer buffer */7 G) H7 V" l1 I) e% z6 n- N5 h0 N/ T
unsigned char _FAR *curp; /* Current active pointer */& g# g7 d2 D- a/ {
unsigned istemp; /* Temporary file indicator */; O8 W# _7 m' z f" p
short token; /* Used for validity checking */
+ l( u* d, S2 a5 q2 t2 z2 c1 X} FILE; /* This is the FILE object */</P>
9 t/ Y1 z2 @9 J \7 X) x6 w' n7 c) s< > FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行,此种文件操作常用的函数见下表 函数 功能
0 i3 P3 K$ [" y$ lfopen() 打开流 7 Y; ^' F8 L& ] c
fclose() 关闭流
; W; w% ]- u* I: G/ A; kfputc() 写一个字符到流中
6 y) c1 ~) J& ^, g3 u1 m [9 Nfgetc() 从流中读一个字符
2 j) x( A D: o4 e) i& kfseek() 在流中定位到指定的字符
u+ I+ [' P, K5 ^: Z* n$ tfputs() 写字符串到流 $ d- k7 R3 p; X- E( y! N2 X
fgets() 从流中读一行或指定个字符 # f# `2 e J1 x" a1 g1 T% ^$ W
fprintf() 按格式输出到流 " r; m) s+ p# o* Z
fscanf() 从流中按格式读取 + ?: q, L2 ?2 R4 ~
feof() 到达文件尾时返回真值
- s4 m2 C& Z$ M& Qferror() 发生错误时返回其值 1 i& N: a9 K% j1 A# G6 Y
rewind() 复位文件定位器到文件开始处 8 G3 C4 Y" v# C4 r
remove() 删除文件
* l: n/ L/ V" Lfread() 从流中读指定个数的字符 # S& c6 _) O! A: Z3 l2 K) t
fwrite() 向流中写指定个数的字符 , a) c- M0 Q" S
tmpfile() 生成一个临时文件流
; D( e7 x U" @tmpnam() 生成一个唯一的文件名 </P> R# N) p* U' R6 X5 q
< >
% I5 i( u4 V1 v3 ^) E 下面就介绍一下这些函数</P>$ Q8 B( J9 Q$ T9 A# `
< >1.fopen()( V" ^+ T3 _& x, ^; @$ L) f: X# m
fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能</P>
' m [7 i9 r3 J2 ]/ \; ?< >为使用而打开一个流 6 j' U. h- r, r8 G
把一个文件和此流相连接 * n' j+ b$ ^: r% g1 G( y# @
给此流返回一个FILR指针* o0 \4 l5 g9 f- \
参数filename指向要打开的文件名,mode表示打开状态的字符串,其取值如下表</P>
# c- ~) ?. _. s' j$ K* X/ K< >字符串 含义
2 v5 U# B4 Q2 f"r" 以只读方式打开文件
0 J1 o5 `, M9 T9 K2 R$ U ~% F"w" 以只写方式打开文件
9 c5 o8 V" X0 U' {"a" 以追加方式打开文件
" T5 ]1 r- z E/ S3 }/ G"r+" 以读/写方式打开文件,如无文件出错 - h. |, P- f$ x, B" W
"w+" 以读/写方式打开文件,如无文件生成新文件 </P>( c, m, n' X0 R4 M7 ]% i/ T
< > 一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符'\n',而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。</P># h; z( {% G/ t- y5 z0 P! X
< > 系统默认的是以文本模式打开,可以修改全部变量_fmode的值来修改这个设置,例如_fmode=O_TEXT;就设置默认打开方式为文本模式;而_fmode=O_BINARY;则设置默认打开方式是二进制模式。</P>3 q: k C/ I( }1 o0 l- u9 r) y4 Y
< > 我们也可以在模式字符串中指定打开的模式,如"rb"表示以二进制模式打开只读文件,"w+t"或"wt+"表示以文本模式打开读/写文件。</P>
) L! q+ G- o4 w/ F$ h- f, V< > 此函数返回一个FILE指针,所以申明一个FILE指针后不用初始化,而是用fopen()来返回一个指针并与一个特定的文件相连,如果成败,返回NULL。</P>
( C& |6 O' t- ?: Z# b7 F< >例:</P>
4 W! s3 I# J6 t4 I< > FILE *fp; 7 D2 J) v L O" x6 k% ?
if(fp=fopen("123.456","wb"))
8 M5 Y, c5 D2 n& H% O. C' [1 q0 E2 ? puts("打开文件成功");1 V' U$ Y, @6 f* V8 U2 R$ l
else ' o8 O2 i: T9 x7 k7 Z3 E8 m
puts("打开文件成败"); </P>4 ? N" h5 F6 ]% x& r, a H6 g
< >2.fclose()
' Z6 i- y+ `% q/ p- G- ^6 s fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。</P>( t& o2 ?- D" j
< > 在程序结束时一定要记得关闭打开的文件,不然可能会造成数据丢失的情况,我以前就经常犯这样的毛病。</P>7 l$ |) B" z& @/ Q5 k" |# N, g( K
< >例:fclose(fp);</P>
1 c* O( b6 g% l1 `8 @< >3.fputc()
! ]0 R2 y, ~" ] t4 S+ J 向流写一个字符,原型是int fputc(int c, FILE *stream); 成功返回这个字符,失败返回EOF。</P>
$ a3 [8 z$ m3 @: P1 P6 H0 V< >例:fputc('X',fp);</P>
- Z& T- _1 t6 {* H8 }! T7 Y< >4.fgetc()
- [1 @4 |/ p! c 从流中读一个字符,原型是int fputc(FILE *stream); 成功返回这个字符,失败返回EOF。</P>
5 o$ _% O* S c0 ?% M< >例:char ch1=fgetc(fp);</P>2 _9 C# E4 _: c. `( ^9 v3 C1 F3 j
< >5. fseek()
, `. C- G# B& o: q: t 此函数一般用于二进制模式打开的文件中,功能是定位到流中指定的位置,原型是int fseek(FILE *stream, long offset, int whence);如果成功返回0,参数offset是移动的字符数,whence是移动的基准,取值是</P>3 Y7 I7 X4 c6 e( s+ P
< >符号常量 值 基准位置 . y" p8 o: J- r1 l3 a2 s" j7 N! y
SEEK_SET 0 文件开头 & d6 _4 v6 ?7 n0 U3 J* V
SEEK_CUR 1 当前读写的位置
4 n, l! v5 d* `5 p* Z# j% G% C" XSEEK_END 2 文件尾部 </P>
+ I4 n: z1 T5 c2 T$ w+ v, y5 b. L9 }< >例:fseek(fp,1234L,SEEK_CUR);//把读写位置从当前位置向后移动1234字节(L后缀表示长整数)</P>
. f5 w; o: U d/ U. E& L< > fseek(fp,0L,2);//把读写位置移动到文件尾</P>
) _3 L" `; U- E1 _" [, Q) Q< >6.fputs()
8 Z; B3 B8 {5 c2 _& v 写一个字符串到流中,原型int fputs(const char *s, FILE *stream); </P>! V! c: E& n. y; }9 C5 [
< >例:fputs("I Love You",fp);</P>2 y, n3 x( e) A1 X' a9 ~. T0 i
< >7.fgets()
9 z1 [; M2 n5 q& u' o 从流中读一行或指定个字符,原型是char *fgets(char *s, int n, FILE *stream); 从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s的指针,否则返回NULL。</P>; B# j8 q2 p0 b& q% V+ \* |$ Y+ B
< >例:如果一个文件的当前位置的文本如下</P>* l( V4 ]$ g2 T1 ]( u6 {6 d2 e
< >Love ,I Have</P>; Y+ d- U' H" n) M
<P>But ........</P>6 w0 V( \" } z8 Q* s- y
<P>如果用</P>- T% [( k8 a9 a* H4 W
<P> fgets(str1,4,file1);</P>
& p- R3 J9 }* N( L<P>则执行后str1="Lov",读取了4-1=3个字符,而如果用</P>9 L- m* W+ |* A Q! F5 x' W
<P> fgets(str1,23,file1);</P>! E) s0 `0 C3 A5 {% j4 o
<P>则执行str="Love ,I Have",读取了一行(不包括行尾的'\n')。</P>4 y% j7 b; \& B
<P>8.fprintf()
& s6 I P+ m7 T0 K 按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了</P>9 u2 V. q/ d; a: `8 M" h- p2 s
<P>例:fprintf(fp,"%2d%s",4,"Hahaha");</P>
& ?4 a4 Y+ o* @; B5 w<P>9.fscanf()
! i1 R5 {* \' ?# Y2 Y; _ 从流中按格式读取,其原型是int fscanf(FILE *stream, const char *format[, address, ...]);其用法和scanf()相同,不过不是从控制台读取,而是从流读取罢了。</P>
2 R" W1 f! ?# H: t<P>例:fscanf(fp,"%d%d" ,&x,&y);</P>! C$ O E' e# V
<P>10.feof()
4 r: j# N( k9 ~, ~ 检测是否已到文件尾,是返回真,否则返回0,其原型是int feof(FILE *stream);</P>6 j* O3 {, u9 y7 E
<P>例:if(feof(fp))printf("已到文件尾");</P>3 Z4 T* r1 m- U
<P>11.ferror()( y5 P1 T5 {) W
原型是int ferror(FILE *stream);返回流最近的错误代码,可用clearerr()来清除它,clearerr()的原型是void clearerr(FILE *stream);</P>
7 y" f" A( w) l x' b; l<P>例:printf("%d",ferror(fp));</P>+ X6 d1 b I9 d
<P>12.rewind()8 Q1 q' X1 U+ i- G6 B+ ?! R
把当前的读写位置回到文件开始,原型是void rewind(FILE *stream);其实本函数相当于fseek(fp,0L,SEEK_SET);</P>
9 j6 g9 d) z' l. C<P>例:rewind(fp);</P>, }& W# F8 b6 d) E
<P>12.remove()0 Q8 ~8 k' O9 U; g9 a4 a- p
删除文件,原型是int remove(const char *filename); 参数就是要删除的文件名,成功返回0。</P>7 @ x: j2 G6 ~1 X
<P>例:remove("c:\\io.sys");</P>7 ~$ d2 r2 u Q; L
<P>13.fread()
' P; A/ }+ v0 L8 U1 F G0 ~ 从流中读指定个数的字符,原型是size_t fread(void *ptr, size_t size, size_t n, FILE *stream);参数ptr是保存读取的数据,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是读取的块数,如果成功,返回实际读取的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>' O6 x/ k, z) P
<P>例:</P>
5 \9 d" E# B6 k( B' A3 k<P> char x[4230];
0 G. k3 V0 Z& {4 t FILE *file1=fopen("c:\\msdos.sys","r");
8 m8 _7 H) [& q fread(x,200,12 ,file1);//共读取200*12=2400个字节</P> s L6 |4 [8 \8 J6 e1 u" Y
<P>14.fwrite()
2 E! v8 W$ y) i; f( ]0 x$ ^ 与fread对应,向流中写指定的数据,原型是size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);参数ptr是要写入的数据指针,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是要写的块数,如果成功,返回实际写入的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>- J! F" d3 @' O5 P
<P>例:</P>
3 P4 ~5 S/ m0 P1 J* {! e2 }$ `<P> char x[]="I Love You";. t: R- b# [5 |. E
fwire(x, 6,12,fp);//写入6*12=72字节</P>: p- q7 B) Y+ S" P# `$ X0 u' l7 }
<P> 将把"I Love"写到流fp中12次,共72字节</P>; @) @3 _' R- u
<P>15.tmpfile()* ~: E% W! |- k) s+ u& D+ ~! X
其原型是FILE *tmpfile(void); 生成一个临时文件,以"w+b"的模式打开,并返回这个临时流的指针,如果失败返回NULL。在程序结束时,这个文件会被自动删除。</P>! ?5 ?; N/ d+ I8 b A* r
<P>例:FILE *fp=tmpfile();</P>
& r- [, S% `0 h; H, b! g, F<P>16.tmpnam();3 a' b# q4 p# O# x& v/ I+ n4 ?. Y+ ^
其原型为char *tmpnam(char *s); 生成一个唯一的文件名,其实tmpfile()就调用了此函数,参数s用来保存得到的文件名,并返回这个指针,如果失败,返回NULL。</P>) `" W' }, f$ a& G7 ?
3 a" s% j$ V# i# m, [6 o6 A<P>
" V: `* j" w1 a4 @ </P> |
zan
|