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

我的地盘我做主
该用户从未签到
 |
< >、基于C的文件操作
9 \8 e5 c$ ?9 O& U( K 在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之。</P>
H( N% f+ [- H" d6 H# `; R$ d< >一、流式文件操作
& v' Y. V: }# N3 ^( m 这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下:</P>
4 { w9 A6 L3 t. |5 r4 k3 \< >typedef struct {9 U$ {) _/ s/ ]$ U8 k& o3 G
int level; /* fill/empty level of buffer */# Z' e+ V- g; Z1 w! u
unsigned flags; /* File status flags */
0 q$ q9 ]' o0 i: y: kchar fd; /* File descriptor */6 u8 l7 D: L/ L8 }& d$ d
unsigned char hold; /* Ungetc char if no buffer */5 E4 u9 P2 h' `0 L1 H$ O7 }
int bsize; /* Buffer size */, H2 ~7 r8 T0 w; `& E2 k, W% w
unsigned char _FAR *buffer; /* Data transfer buffer */6 N4 S W D$ x+ J/ v
unsigned char _FAR *curp; /* Current active pointer */2 c5 x( o6 [! X7 Y1 X" O) [
unsigned istemp; /* Temporary file indicator */
" {; |. B6 u4 o2 g% H! Kshort token; /* Used for validity checking */' u3 V+ Y9 L6 \$ D: e7 e
} FILE; /* This is the FILE object */</P>
& {, O8 X* r, r( f$ H' [< > FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行,此种文件操作常用的函数见下表 函数 功能
) ~) j7 G. u4 j6 [ `fopen() 打开流
5 P: N( \! ]7 zfclose() 关闭流 ; v; {/ U: Z; b3 L0 ]
fputc() 写一个字符到流中 " g* y) K4 X% C/ ^' `9 n% i
fgetc() 从流中读一个字符
" W) J3 Z! o0 ~0 C, u3 J( P& bfseek() 在流中定位到指定的字符
- W- b: T" }% t5 _4 ufputs() 写字符串到流 : D5 P: V. y! j9 m( K- y* Z) B. W
fgets() 从流中读一行或指定个字符
5 ]" d8 T! e& r& nfprintf() 按格式输出到流
' p3 B) t: G* ~( N+ P Y* X2 jfscanf() 从流中按格式读取 1 ~5 {, _6 ~5 C/ f/ D& }- u7 q
feof() 到达文件尾时返回真值 $ m: I* H$ `# Q7 M+ k7 X; V" [
ferror() 发生错误时返回其值
: P% p* y: j; G) {9 d5 m/ A$ a$ frewind() 复位文件定位器到文件开始处 4 x; |6 i$ Y' ^ q9 v
remove() 删除文件 ) ?+ | e3 e0 {3 t- I; u
fread() 从流中读指定个数的字符
, V! U6 A1 W) w9 n6 ]+ wfwrite() 向流中写指定个数的字符 ) R" {/ m x, E: V
tmpfile() 生成一个临时文件流 * A- N* c" d6 l j* `7 q
tmpnam() 生成一个唯一的文件名 </P>
! T+ E; v8 F4 n( ^: d7 ~ J, n< >8 w! E2 m' H6 e$ h% w& `* r! O& R' A
下面就介绍一下这些函数</P>- D9 |6 t0 Y; o' S9 D
< >1.fopen()9 U9 ~* L) J% F1 ]0 u" a2 E/ v# P
fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能</P>
& Q8 k6 V3 C2 c7 ^) {< >为使用而打开一个流 9 S) I2 F% Y; `6 s
把一个文件和此流相连接 0 a" d# P9 s3 ~7 y6 w1 H3 j& l
给此流返回一个FILR指针, }/ g- b2 n8 E
参数filename指向要打开的文件名,mode表示打开状态的字符串,其取值如下表</P>5 P) t" S c* \' e* B6 g" `% V
< >字符串 含义 9 v5 N8 |3 F6 J2 O2 k- F5 x$ B
"r" 以只读方式打开文件
$ n- D1 j8 V N5 r8 {% O* k1 D"w" 以只写方式打开文件
: v( I2 D7 g* i"a" 以追加方式打开文件 7 ? g. b% E0 u' ?
"r+" 以读/写方式打开文件,如无文件出错 2 \3 p5 i) r9 M1 V
"w+" 以读/写方式打开文件,如无文件生成新文件 </P>
% V! e2 i; i9 ^$ i8 G- h1 p' r ?< > 一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符'\n',而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。</P>
- e/ O( O, o) ]< > 系统默认的是以文本模式打开,可以修改全部变量_fmode的值来修改这个设置,例如_fmode=O_TEXT;就设置默认打开方式为文本模式;而_fmode=O_BINARY;则设置默认打开方式是二进制模式。</P>( a$ k n5 M& l4 k) P
< > 我们也可以在模式字符串中指定打开的模式,如"rb"表示以二进制模式打开只读文件,"w+t"或"wt+"表示以文本模式打开读/写文件。</P>4 k$ c2 z& y4 {
< > 此函数返回一个FILE指针,所以申明一个FILE指针后不用初始化,而是用fopen()来返回一个指针并与一个特定的文件相连,如果成败,返回NULL。</P>
! P6 Y9 G( u' _: A" l2 w< >例:</P>
# E" ?, L% t6 _3 e< > FILE *fp; T- ]% s% r* y
if(fp=fopen("123.456","wb"))/ C' ~" e% @! U9 n' F! n- f
puts("打开文件成功");1 F; M( O& L+ J% P
else ! d$ V/ S% ^% N1 a
puts("打开文件成败"); </P>
. }. A( g! Z4 W< >2.fclose()
$ F% Y M# Q( m3 i$ X fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。</P>+ X' h) Q6 V& Y/ k. G: O. D! }
< > 在程序结束时一定要记得关闭打开的文件,不然可能会造成数据丢失的情况,我以前就经常犯这样的毛病。</P>
; J1 F- \# O0 R1 n- G7 O1 f( F2 A< >例:fclose(fp);</P>
9 C# I: D6 v1 s( C/ V# L7 F! [/ I< >3.fputc()+ O7 o; z- v% e, o& s9 _: F
向流写一个字符,原型是int fputc(int c, FILE *stream); 成功返回这个字符,失败返回EOF。</P>+ Q4 q; S: t8 K6 O M
< >例:fputc('X',fp);</P>- s! F- S2 O$ S7 O2 d
< >4.fgetc()
7 Q% [6 y3 ~; | 从流中读一个字符,原型是int fputc(FILE *stream); 成功返回这个字符,失败返回EOF。</P>6 E$ q% l4 n# ?4 O
< >例:char ch1=fgetc(fp);</P>5 M+ k" ?! S5 `2 H( }
< >5. fseek(); B, `4 Y; ], d
此函数一般用于二进制模式打开的文件中,功能是定位到流中指定的位置,原型是int fseek(FILE *stream, long offset, int whence);如果成功返回0,参数offset是移动的字符数,whence是移动的基准,取值是</P>
0 S* X1 J: t7 b4 \/ B- x+ f< >符号常量 值 基准位置 4 I5 M6 V9 w( \" t6 ^8 {# U; H# C
SEEK_SET 0 文件开头 ! y) c; t) N& [7 X s
SEEK_CUR 1 当前读写的位置
2 q& U# I& p8 g! E" t: TSEEK_END 2 文件尾部 </P>
3 [/ i8 `9 f+ ~5 Z+ R< >例:fseek(fp,1234L,SEEK_CUR);//把读写位置从当前位置向后移动1234字节(L后缀表示长整数)</P>
) B" y& w( M. G< > fseek(fp,0L,2);//把读写位置移动到文件尾</P>
' n0 ~) N% ?: B* A5 @; e< >6.fputs()& o) ?3 I% D" G+ W4 \2 k* a' l
写一个字符串到流中,原型int fputs(const char *s, FILE *stream); </P>
& @1 P0 }( }! V6 K< >例:fputs("I Love You",fp);</P>7 U% A- u" E. }/ d& @
< >7.fgets()
0 r$ g4 s1 B8 A$ S7 Y2 E0 k% n 从流中读一行或指定个字符,原型是char *fgets(char *s, int n, FILE *stream); 从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s的指针,否则返回NULL。</P>( ]5 r# b& @# \+ y; Z( U
< >例:如果一个文件的当前位置的文本如下</P>* {- H$ {7 O: I% k) i2 J1 d4 g
< >Love ,I Have</P>! ?/ Z6 S {9 H& b
<P>But ........</P>
! I4 |1 S4 X) h: c<P>如果用</P>7 t- r& I$ A# v8 o- S
<P> fgets(str1,4,file1);</P>
6 Y: P3 w- s3 h3 N } E" t7 B# ~<P>则执行后str1="Lov",读取了4-1=3个字符,而如果用</P>
. g3 q3 i: |5 S, Z; ~<P> fgets(str1,23,file1);</P>* |& `6 z9 z ~& M
<P>则执行str="Love ,I Have",读取了一行(不包括行尾的'\n')。</P>
& w# Q7 M. A. `5 [2 t<P>8.fprintf()& ?: e6 K% [( k! S. j6 j% r
按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了</P>" ^0 w$ M- j. h, h2 K0 Y* g/ ]
<P>例:fprintf(fp,"%2d%s",4,"Hahaha");</P>
: |. Q3 Z S5 i" H' d5 Y, i<P>9.fscanf()
0 q) w5 Z/ W5 T& D( d 从流中按格式读取,其原型是int fscanf(FILE *stream, const char *format[, address, ...]);其用法和scanf()相同,不过不是从控制台读取,而是从流读取罢了。</P>8 _% v1 T/ e" M$ x1 O/ d3 E/ q1 U
<P>例:fscanf(fp,"%d%d" ,&x,&y);</P>
/ \7 q5 l5 Y4 l<P>10.feof()$ x% Y8 p4 o u2 Y
检测是否已到文件尾,是返回真,否则返回0,其原型是int feof(FILE *stream);</P>
3 e- @6 }7 {3 ]7 a s# N<P>例:if(feof(fp))printf("已到文件尾");</P>/ k# P# u! V. }% U
<P>11.ferror()0 _+ W) H# r2 [0 d# Y- R! M; N
原型是int ferror(FILE *stream);返回流最近的错误代码,可用clearerr()来清除它,clearerr()的原型是void clearerr(FILE *stream);</P>8 q/ V1 X. H$ W u
<P>例:printf("%d",ferror(fp));</P>& {# ?0 ~0 M8 X1 Q" v: I
<P>12.rewind()7 u: a# {7 h. e" h0 V
把当前的读写位置回到文件开始,原型是void rewind(FILE *stream);其实本函数相当于fseek(fp,0L,SEEK_SET);</P>
) o* V1 q" N* j<P>例:rewind(fp);</P>
5 w2 ~9 U& A' e# I* h<P>12.remove()' T2 U+ }' g, l, F, Z
删除文件,原型是int remove(const char *filename); 参数就是要删除的文件名,成功返回0。</P>
5 g" _' O# {* X: q J7 {8 f7 j<P>例:remove("c:\\io.sys");</P>6 G, q) R% c4 p, G& C4 T2 z
<P>13.fread(). ^, ?. D6 l/ M* e1 J
从流中读指定个数的字符,原型是size_t fread(void *ptr, size_t size, size_t n, FILE *stream);参数ptr是保存读取的数据,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是读取的块数,如果成功,返回实际读取的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>
( b: E4 @: g/ @2 Q<P>例:</P>; A& K( l* S; z: O3 h! L8 G
<P> char x[4230];0 I h1 c8 g4 Q( ~! H
FILE *file1=fopen("c:\\msdos.sys","r");* C7 Z7 E) b: ^" `; z( J$ M
fread(x,200,12 ,file1);//共读取200*12=2400个字节</P>
% X9 F" V/ [' P* m; \. ]<P>14.fwrite()" ^ W' @( a: [9 E- Z& @ I6 q+ q
与fread对应,向流中写指定的数据,原型是size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);参数ptr是要写入的数据指针,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是要写的块数,如果成功,返回实际写入的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>
2 U9 E$ D! o& k$ J. q0 X6 o/ D<P>例:</P>0 _' U9 {2 N2 O6 E. L( A' S
<P> char x[]="I Love You";3 L& {- ~5 U9 h/ s
fwire(x, 6,12,fp);//写入6*12=72字节</P>$ V. u5 y+ N: |; u- K3 m" N
<P> 将把"I Love"写到流fp中12次,共72字节</P>
( v& b! o, m, P6 H; Y2 t* I A<P>15.tmpfile()( X' V6 O2 _! r/ {( s, |
其原型是FILE *tmpfile(void); 生成一个临时文件,以"w+b"的模式打开,并返回这个临时流的指针,如果失败返回NULL。在程序结束时,这个文件会被自动删除。</P>
5 ]4 Q9 o8 J& O" A% j$ [<P>例:FILE *fp=tmpfile();</P>
6 h# r! l$ h1 O$ H( I2 F3 b<P>16.tmpnam();
7 Z2 l& {( e" H; n* h& ?, u i 其原型为char *tmpnam(char *s); 生成一个唯一的文件名,其实tmpfile()就调用了此函数,参数s用来保存得到的文件名,并返回这个指针,如果失败,返回NULL。</P>" a8 O4 ?( q, m' W1 k
9 T* {) k: g ?% y+ h<P>
' f, \8 A# Q/ z0 j. _ </P> |
zan
|