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

我的地盘我做主
该用户从未签到
 |
< >、基于C的文件操作 3 v( I( j p) ~
在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之。</P>. V( A* }" ~/ I
< >一、流式文件操作
9 Z( k& [2 a5 D; C5 D4 E 这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下:</P>
8 B- ^7 f! ?, O8 T! ~, t. d% O< >typedef struct {, g" U6 X* c3 ]! A$ H t' {
int level; /* fill/empty level of buffer */
6 v+ V: g, i- vunsigned flags; /* File status flags */5 ?# h0 w$ x6 g5 ^
char fd; /* File descriptor */
3 s2 R& j5 g3 E7 S; T, ounsigned char hold; /* Ungetc char if no buffer */
+ _, o6 F. _% e+ w% ^3 vint bsize; /* Buffer size */- P Q1 i3 H8 f6 u8 d1 \' \
unsigned char _FAR *buffer; /* Data transfer buffer */
/ {% x' b9 \% y6 i0 e/ r% tunsigned char _FAR *curp; /* Current active pointer */
# Z& }1 K; ^- X2 i, U" H- _unsigned istemp; /* Temporary file indicator */' F" q; \" {; e w+ N/ `8 R( J
short token; /* Used for validity checking */
* T) q" V% S6 K* s- N} FILE; /* This is the FILE object */</P>
( L$ t1 _5 z% _9 k- ?# n* J< > FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行,此种文件操作常用的函数见下表 函数 功能
& H3 H/ b) w! Z! H* e" T' |! ]fopen() 打开流
0 N( J$ Y" R. jfclose() 关闭流
, Q- [# `$ o9 r) p9 H pfputc() 写一个字符到流中 8 p& b9 y6 g, v- F5 T5 A/ @9 _" ?. V% H1 p
fgetc() 从流中读一个字符
4 f: D" \1 c. |/ Qfseek() 在流中定位到指定的字符 $ @+ W2 P' L* C7 c) [) s2 ~
fputs() 写字符串到流 2 U' }; R+ H: t8 D" P K
fgets() 从流中读一行或指定个字符
" Y$ }. ^) U9 r$ Wfprintf() 按格式输出到流 / p- y* ^; j! |; P. R& R; z
fscanf() 从流中按格式读取 k {- P+ y* d1 Q0 p V s6 F% q
feof() 到达文件尾时返回真值
, E+ x( t- e6 v. R" t) @" x# Eferror() 发生错误时返回其值 2 T& h3 b) v8 N9 i+ e
rewind() 复位文件定位器到文件开始处
! O+ ]/ A1 p/ ~remove() 删除文件
5 ?2 g6 H0 i6 yfread() 从流中读指定个数的字符 + K+ v! J# }1 V0 p/ W0 r Q& q+ H
fwrite() 向流中写指定个数的字符 & L# G; h* g5 k! Z6 w( }# w6 j
tmpfile() 生成一个临时文件流 9 H9 F- z1 ?' m4 S" f! f+ `
tmpnam() 生成一个唯一的文件名 </P>
5 \$ ~0 `# @% u8 U% s4 [" p) \< >4 W' o6 m5 l" a
下面就介绍一下这些函数</P>
( l- f5 F% n& U8 A) ]< >1.fopen()* z8 v; ?5 \* X( @
fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能</P>! f" @& E! K! P, g& L
< >为使用而打开一个流 0 W6 q# U7 `. Y( {$ |% [. ^* j- x
把一个文件和此流相连接 : F7 j3 R; z# ] n( t/ h/ R
给此流返回一个FILR指针' y/ q) J, _/ f/ C' N2 N" E
参数filename指向要打开的文件名,mode表示打开状态的字符串,其取值如下表</P>
% z8 r. {0 R6 b$ }/ M6 ]! f< >字符串 含义
, m3 |! q7 V7 s- t8 x$ d"r" 以只读方式打开文件 ! p, W$ @2 K2 d( a8 r8 J
"w" 以只写方式打开文件 & b0 l1 C2 i" N) z
"a" 以追加方式打开文件 0 g, z% w3 D; h1 }% _
"r+" 以读/写方式打开文件,如无文件出错
" H7 h! v4 F" C' d5 J"w+" 以读/写方式打开文件,如无文件生成新文件 </P>" N9 p0 S) A4 E2 E8 P" I6 x
< > 一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符'\n',而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。</P>
5 {. F4 J& ^* j, o2 V" B< > 系统默认的是以文本模式打开,可以修改全部变量_fmode的值来修改这个设置,例如_fmode=O_TEXT;就设置默认打开方式为文本模式;而_fmode=O_BINARY;则设置默认打开方式是二进制模式。</P>
6 W) G( P h# T0 a7 e2 t' _0 \2 B< > 我们也可以在模式字符串中指定打开的模式,如"rb"表示以二进制模式打开只读文件,"w+t"或"wt+"表示以文本模式打开读/写文件。</P>
: i/ m$ d" w# M# H. i0 w, a# ?" [& F< > 此函数返回一个FILE指针,所以申明一个FILE指针后不用初始化,而是用fopen()来返回一个指针并与一个特定的文件相连,如果成败,返回NULL。</P>/ L1 E g4 C+ U' O0 @1 ?
< >例:</P>
' _/ M X) u- R/ c< > FILE *fp; 1 c2 s' {" ]& {6 Q! \
if(fp=fopen("123.456","wb"))7 `4 P8 B# d$ \0 Y, o; V
puts("打开文件成功");! P( F; f' q2 q
else $ b3 h6 y a+ k& m
puts("打开文件成败"); </P>, y$ x q) h# i8 ?- O+ I$ {
< >2.fclose()
; a2 w+ M. O7 U) I* k) B5 y& L fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。</P>
1 u* s6 X4 N7 d, A2 s2 P- }8 t- g< > 在程序结束时一定要记得关闭打开的文件,不然可能会造成数据丢失的情况,我以前就经常犯这样的毛病。</P>4 @* ?1 [% ^* |& V G( q3 M4 L) H
< >例:fclose(fp);</P>1 ]- a9 d9 G4 a: o- }
< >3.fputc()6 J5 f6 @$ v' {/ H9 T, f2 w% P
向流写一个字符,原型是int fputc(int c, FILE *stream); 成功返回这个字符,失败返回EOF。</P>, r, B9 U# z$ T0 R
< >例:fputc('X',fp);</P>+ D0 K5 f- U7 H
< >4.fgetc()
+ H$ V: }8 Z* H8 h9 |6 X 从流中读一个字符,原型是int fputc(FILE *stream); 成功返回这个字符,失败返回EOF。</P>
) h2 q# m6 m0 s, y< >例:char ch1=fgetc(fp);</P>
2 c: g) _4 Z- P5 K' S9 C< >5. fseek(), k0 ~9 T4 ^0 Q+ G
此函数一般用于二进制模式打开的文件中,功能是定位到流中指定的位置,原型是int fseek(FILE *stream, long offset, int whence);如果成功返回0,参数offset是移动的字符数,whence是移动的基准,取值是</P>9 @: G b$ |) s$ M
< >符号常量 值 基准位置 2 V) O' u5 B, f0 j* _
SEEK_SET 0 文件开头
+ ]9 J7 y2 ?! z$ m4 @SEEK_CUR 1 当前读写的位置
* ~2 q6 \4 \' fSEEK_END 2 文件尾部 </P>$ j6 {1 a" f! n5 X' t
< >例:fseek(fp,1234L,SEEK_CUR);//把读写位置从当前位置向后移动1234字节(L后缀表示长整数)</P>- ?1 K$ `, s/ Z) ^" ~6 e
< > fseek(fp,0L,2);//把读写位置移动到文件尾</P>
: _; }: K' D9 e* B& p% V8 B2 B) M< >6.fputs()
! B- N+ ]5 P: q9 ?' H* X/ E- t 写一个字符串到流中,原型int fputs(const char *s, FILE *stream); </P>5 F" b- ^ w4 @" k
< >例:fputs("I Love You",fp);</P>
* Z) x5 m) p+ \* ]% ?< >7.fgets()% n1 ^4 Q9 V; ~" \9 i- h6 f5 ~
从流中读一行或指定个字符,原型是char *fgets(char *s, int n, FILE *stream); 从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s的指针,否则返回NULL。</P>
4 C0 v8 g v7 E# H$ T/ D! j< >例:如果一个文件的当前位置的文本如下</P>
' t% s$ J6 X% _3 K) z* b< >Love ,I Have</P>5 A# t' |! H9 Y" u% x/ [" b4 j1 D
<P>But ........</P>
5 _; L6 B2 K0 ?1 k( j4 H$ ]<P>如果用</P>
6 ]) f5 u6 e; h$ H6 b; _ x9 h<P> fgets(str1,4,file1);</P>+ r( Y4 z( e1 g1 \3 ]
<P>则执行后str1="Lov",读取了4-1=3个字符,而如果用</P>, {2 J9 v4 U1 Q
<P> fgets(str1,23,file1);</P>
2 ~: I2 u& L( L/ K$ O" U4 G<P>则执行str="Love ,I Have",读取了一行(不包括行尾的'\n')。</P>
) V. m' t; o7 D, m% G<P>8.fprintf()
$ H& m# F0 y' B5 o 按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了</P>" N F$ E. {4 m1 v
<P>例:fprintf(fp,"%2d%s",4,"Hahaha");</P>: s2 ~, F# r# G( i8 [" W7 [* S8 [
<P>9.fscanf()
9 N3 e4 I( ` S: d6 N, R 从流中按格式读取,其原型是int fscanf(FILE *stream, const char *format[, address, ...]);其用法和scanf()相同,不过不是从控制台读取,而是从流读取罢了。</P>' Z# e$ e( Z2 C, o8 `( X
<P>例:fscanf(fp,"%d%d" ,&x,&y);</P>
% I& r, |0 ]% p& E$ Z<P>10.feof()
. j, M( V" v& n6 ~4 M/ ^ 检测是否已到文件尾,是返回真,否则返回0,其原型是int feof(FILE *stream);</P>, I( G6 }. N$ q* i) D! m
<P>例:if(feof(fp))printf("已到文件尾");</P>! t+ w0 Q' k% y9 \4 d" j9 h& O
<P>11.ferror()
3 Z# H( E1 v" n! y3 B' Y 原型是int ferror(FILE *stream);返回流最近的错误代码,可用clearerr()来清除它,clearerr()的原型是void clearerr(FILE *stream);</P>2 A: s; D( O# J3 y9 {5 l
<P>例:printf("%d",ferror(fp));</P>
" y ]: j7 G% m. j<P>12.rewind()6 U' Q3 q2 L. ~9 L. M* v: c
把当前的读写位置回到文件开始,原型是void rewind(FILE *stream);其实本函数相当于fseek(fp,0L,SEEK_SET);</P>
S4 ?" [: o$ u' o' ]<P>例:rewind(fp);</P>
/ f, t1 {0 p7 e" B! z: @! F<P>12.remove()
/ j+ j5 Y. o# n# m9 v 删除文件,原型是int remove(const char *filename); 参数就是要删除的文件名,成功返回0。</P>
5 Y. ^2 ~0 y$ U3 P- u<P>例:remove("c:\\io.sys");</P>; x1 {4 r2 _) Y1 s l* ^% O- e, m
<P>13.fread()
2 J1 l6 | F' F, |, a 从流中读指定个数的字符,原型是size_t fread(void *ptr, size_t size, size_t n, FILE *stream);参数ptr是保存读取的数据,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是读取的块数,如果成功,返回实际读取的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>
. X$ ~4 m0 B9 n6 `; s<P>例:</P>
, j e% }! b6 j1 A% Y b<P> char x[4230];
8 y+ z5 V1 w% D. o A" m f, ` FILE *file1=fopen("c:\\msdos.sys","r");/ T4 \5 O" [5 v6 ?
fread(x,200,12 ,file1);//共读取200*12=2400个字节</P>
* ? P* C' G# P8 @/ p1 Y$ F<P>14.fwrite()% k4 R0 K, _. x9 j9 ^
与fread对应,向流中写指定的数据,原型是size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);参数ptr是要写入的数据指针,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是要写的块数,如果成功,返回实际写入的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>. p; B4 S7 Q/ H4 ?# q- |. L, `
<P>例:</P>/ E1 C3 c( b# [8 i0 s3 s
<P> char x[]="I Love You";
# {" Z6 Z* r& g' q fwire(x, 6,12,fp);//写入6*12=72字节</P>
* [# g0 o9 j' E! g' ~% \9 E3 E<P> 将把"I Love"写到流fp中12次,共72字节</P>
8 A: L* i' w+ F; r9 t<P>15.tmpfile()
" \8 }/ B* V# P" |( ~3 N/ k 其原型是FILE *tmpfile(void); 生成一个临时文件,以"w+b"的模式打开,并返回这个临时流的指针,如果失败返回NULL。在程序结束时,这个文件会被自动删除。</P>1 d; M* E* Q% x
<P>例:FILE *fp=tmpfile();</P>
2 `5 v1 E' p: i$ H<P>16.tmpnam();$ i' o$ {' v3 ~% a9 j% s2 s
其原型为char *tmpnam(char *s); 生成一个唯一的文件名,其实tmpfile()就调用了此函数,参数s用来保存得到的文件名,并返回这个指针,如果失败,返回NULL。</P>1 n" k; G2 ^& G6 U# a
/ C7 Y6 s/ g( w( c* n( A<P>
/ Z8 `- k4 V% R. U# z! N </P> |
zan
|