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

我的地盘我做主
该用户从未签到
 |
< >、基于C的文件操作 2 h- V1 l7 z4 J( m# h
在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之。</P>' W8 i& }5 p7 K$ l6 ^1 U: Y2 U. b
< >一、流式文件操作8 u! S3 J f, w" m. t
这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下:</P>) I. L; n4 _6 n* B# B- B
< >typedef struct {, l* J# \' n; s' M( g8 `5 G! e
int level; /* fill/empty level of buffer */: h9 T* j. n% j* L" s
unsigned flags; /* File status flags */) c) v4 T( {; L% Q
char fd; /* File descriptor */
, ]& h* K" k" Z" c8 y$ O" |unsigned char hold; /* Ungetc char if no buffer */' m2 _5 P5 Y7 U q3 `+ U7 v
int bsize; /* Buffer size */; w' g( G6 f9 `1 p5 F
unsigned char _FAR *buffer; /* Data transfer buffer *// I6 E6 T3 l$ t9 C
unsigned char _FAR *curp; /* Current active pointer */$ u/ z! G; Z3 w( S
unsigned istemp; /* Temporary file indicator */
3 J2 ^4 G3 a: ~# h, ]$ b( q: kshort token; /* Used for validity checking */
$ W& H: ?# V. D5 Y, |} FILE; /* This is the FILE object */</P>
. |, ^0 M$ n6 A% p< > FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行,此种文件操作常用的函数见下表 函数 功能 ( U/ v0 k* k" q/ G4 `
fopen() 打开流 * {' b4 P% L, t0 u4 k
fclose() 关闭流
# u% _" G& S( H+ Qfputc() 写一个字符到流中 - e/ s9 R" c) m& T0 ?0 U
fgetc() 从流中读一个字符 6 B: m0 ?5 w7 M/ ~
fseek() 在流中定位到指定的字符
$ J0 l6 N Q! z1 c9 _, Z( }fputs() 写字符串到流
% r1 v. b2 X9 g2 m* O/ z( }fgets() 从流中读一行或指定个字符 ) \$ k; S2 ]0 R
fprintf() 按格式输出到流
: `! Q; w0 E7 H- p5 G" ?9 A1 ~fscanf() 从流中按格式读取 ( \( B6 _0 H' I# H; b' ~
feof() 到达文件尾时返回真值 + S a9 W; J6 r7 a
ferror() 发生错误时返回其值
* l$ j9 t- b: k7 l8 u a7 m( f# brewind() 复位文件定位器到文件开始处 9 Q! |: t; Y' z, ?/ o
remove() 删除文件 2 ~3 i: }# o8 n5 ~* t$ ]" h
fread() 从流中读指定个数的字符
7 T6 k8 q! s6 f( ^, nfwrite() 向流中写指定个数的字符
1 s9 a9 }: W! Z7 E4 Htmpfile() 生成一个临时文件流 / _! I! D( @5 H/ G, x
tmpnam() 生成一个唯一的文件名 </P>
7 T/ U! s9 L- }+ }) C( h! Z< > [- B7 C/ w) c' N! t# g9 J2 q7 U
下面就介绍一下这些函数</P>
% v. w4 L' q( `9 Q" I2 D< >1.fopen()
; O7 c1 h) x3 I fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能</P># A6 {* Z# j {6 `1 z. u
< >为使用而打开一个流 ' y: c I7 ~% G" N; q" h
把一个文件和此流相连接
/ N8 Q5 ?; T. d1 s. B" f& E给此流返回一个FILR指针
! `; @4 C7 Z8 ~' G+ Y) J参数filename指向要打开的文件名,mode表示打开状态的字符串,其取值如下表</P>% x/ H8 j8 S k& j3 ]
< >字符串 含义 7 \0 b0 F+ C; s
"r" 以只读方式打开文件
7 X$ k. [! H- {/ O1 ~"w" 以只写方式打开文件
* ^% z) [1 Z r" ^/ l"a" 以追加方式打开文件 7 l: k! c4 V2 f! ? p! [% h
"r+" 以读/写方式打开文件,如无文件出错 & O" i' x! m, Q! }& V
"w+" 以读/写方式打开文件,如无文件生成新文件 </P>
2 G. A9 Z: E& y6 I3 b< > 一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符'\n',而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。</P>, D( J! T- |( U+ E: e4 }7 |7 A7 w
< > 系统默认的是以文本模式打开,可以修改全部变量_fmode的值来修改这个设置,例如_fmode=O_TEXT;就设置默认打开方式为文本模式;而_fmode=O_BINARY;则设置默认打开方式是二进制模式。</P>+ G8 v; p0 G4 c/ J- u
< > 我们也可以在模式字符串中指定打开的模式,如"rb"表示以二进制模式打开只读文件,"w+t"或"wt+"表示以文本模式打开读/写文件。</P>* F$ W6 T; B }- B6 z3 Q
< > 此函数返回一个FILE指针,所以申明一个FILE指针后不用初始化,而是用fopen()来返回一个指针并与一个特定的文件相连,如果成败,返回NULL。</P>
5 T7 Q4 Z& ^0 ?4 T< >例:</P>6 r5 R1 a9 X! y, T- |" h( t
< > FILE *fp;
# {- h+ `0 Q* \0 c* S$ h. ? if(fp=fopen("123.456","wb")); g; Z3 _* Y. t. M' e. ^' P
puts("打开文件成功");
6 B1 M$ y( T2 X) s, i4 I' {- T' n else
1 O9 o* g1 w* | puts("打开文件成败"); </P>( a8 ^! y f! p
< >2.fclose() . F* @" I; _! Z Z- l' F0 m" C
fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。</P>$ v- B. n& x1 e! i
< > 在程序结束时一定要记得关闭打开的文件,不然可能会造成数据丢失的情况,我以前就经常犯这样的毛病。</P>4 p4 N. `( b" b" x& b# \) f7 N
< >例:fclose(fp);</P>& Q0 e- g. N. ]
< >3.fputc()$ ~5 c$ `, f! d- l0 z( T
向流写一个字符,原型是int fputc(int c, FILE *stream); 成功返回这个字符,失败返回EOF。</P>7 B0 j2 Z2 D# M: V. @9 C5 v- X
< >例:fputc('X',fp);</P># l* Y( S5 a; o4 Z% H! d: r
< >4.fgetc()
0 A/ R9 |+ P( U, y# B& h" v7 i 从流中读一个字符,原型是int fputc(FILE *stream); 成功返回这个字符,失败返回EOF。</P>5 ?: H8 A, ?- ?- K
< >例:char ch1=fgetc(fp);</P>
! F/ ?5 ^" u+ N( a< >5. fseek(); Z" E& P3 k: r, t( Q X' F
此函数一般用于二进制模式打开的文件中,功能是定位到流中指定的位置,原型是int fseek(FILE *stream, long offset, int whence);如果成功返回0,参数offset是移动的字符数,whence是移动的基准,取值是</P>
& f! M$ H+ E) p< >符号常量 值 基准位置 / C, i+ E, t0 G: q s8 X+ d
SEEK_SET 0 文件开头 5 D- l, u2 ~# w! d" |3 ^
SEEK_CUR 1 当前读写的位置 9 ~9 W6 D+ }1 W L$ s+ S
SEEK_END 2 文件尾部 </P>
/ k; M, @+ g! S< >例:fseek(fp,1234L,SEEK_CUR);//把读写位置从当前位置向后移动1234字节(L后缀表示长整数)</P>" L2 S! C! ^2 f6 r& t
< > fseek(fp,0L,2);//把读写位置移动到文件尾</P>
4 u( ~6 K! b) | i5 g0 v< >6.fputs()$ [& R# d" T" H2 j3 {8 D
写一个字符串到流中,原型int fputs(const char *s, FILE *stream); </P>8 n7 L: j; Z+ u( s
< >例:fputs("I Love You",fp);</P>
4 V6 G( ~. O7 o< >7.fgets(). i0 s) r0 E- w) x M7 f. I
从流中读一行或指定个字符,原型是char *fgets(char *s, int n, FILE *stream); 从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s的指针,否则返回NULL。</P>
% r% _# o+ b! k5 w# S: l2 a< >例:如果一个文件的当前位置的文本如下</P>7 D" ~) C" ^' J: A; k" e/ `/ d6 b: }
< >Love ,I Have</P>* m5 C1 n D( J/ s3 @
<P>But ........</P>' P5 ], t/ L _( W1 H7 s/ t' }& J
<P>如果用</P>9 t% A0 P5 a, }# I W7 N9 ], y! m7 V
<P> fgets(str1,4,file1);</P>
. G+ G4 A+ u! p, @: V<P>则执行后str1="Lov",读取了4-1=3个字符,而如果用</P>
; g6 a6 h H: I" W; d<P> fgets(str1,23,file1);</P>
, y# t+ d- N9 m+ F<P>则执行str="Love ,I Have",读取了一行(不包括行尾的'\n')。</P>
& g* N. a/ ~ K2 l6 L<P>8.fprintf()
! m% |' D1 L# r- J3 A1 u( X- g% x 按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了</P>2 Z( u5 L5 {, j% \1 k
<P>例:fprintf(fp,"%2d%s",4,"Hahaha");</P>5 c( O; T' h) `1 e \, G
<P>9.fscanf()! a: f) g% E0 u' j
从流中按格式读取,其原型是int fscanf(FILE *stream, const char *format[, address, ...]);其用法和scanf()相同,不过不是从控制台读取,而是从流读取罢了。</P>8 _; X* r$ J( k! k3 W# {
<P>例:fscanf(fp,"%d%d" ,&x,&y);</P>
- _: l1 ]$ f3 x& E1 X: A' {<P>10.feof()8 J2 N, \3 m6 N/ e
检测是否已到文件尾,是返回真,否则返回0,其原型是int feof(FILE *stream);</P>
( Z4 \1 ?+ g! E' O' ^; e* x<P>例:if(feof(fp))printf("已到文件尾");</P>
7 Z- T3 Z4 _. s" P8 V8 B<P>11.ferror()5 a2 o7 {4 g, G5 a2 z
原型是int ferror(FILE *stream);返回流最近的错误代码,可用clearerr()来清除它,clearerr()的原型是void clearerr(FILE *stream);</P>
. d7 R) ]& v. ]* N' Q8 _, b& i<P>例:printf("%d",ferror(fp));</P>7 ^4 o* D$ }1 ]8 I* K' v( G" U1 T: }
<P>12.rewind()
. X/ G, k# E/ _% S8 Z5 Z 把当前的读写位置回到文件开始,原型是void rewind(FILE *stream);其实本函数相当于fseek(fp,0L,SEEK_SET);</P>
- L! _2 q5 @/ E( \& v* D4 ~3 l<P>例:rewind(fp);</P>
7 ^. ^$ x- f+ V) Y \<P>12.remove()+ L/ z$ g _1 Z; R
删除文件,原型是int remove(const char *filename); 参数就是要删除的文件名,成功返回0。</P>2 n7 `0 c) A/ C* Z. P
<P>例:remove("c:\\io.sys");</P>! A" g; a) P' O2 e5 D% i
<P>13.fread()
7 }1 Z6 |* B. o9 I9 S) w. v- j, b E 从流中读指定个数的字符,原型是size_t fread(void *ptr, size_t size, size_t n, FILE *stream);参数ptr是保存读取的数据,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是读取的块数,如果成功,返回实际读取的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>, i P0 S% _, v2 ^0 v5 _
<P>例:</P>
% V- ?# X$ T. q! J+ m<P> char x[4230];. m$ @5 B) E# V1 E0 @7 ^9 b
FILE *file1=fopen("c:\\msdos.sys","r");
$ E$ c7 S' U3 y fread(x,200,12 ,file1);//共读取200*12=2400个字节</P>
) I7 C; R& {4 k2 K<P>14.fwrite()
; }9 } G& F8 t 与fread对应,向流中写指定的数据,原型是size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);参数ptr是要写入的数据指针,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是要写的块数,如果成功,返回实际写入的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>0 X- {% I, E$ V/ d
<P>例:</P>
4 y6 U/ e+ |6 y8 r4 }1 o8 b<P> char x[]="I Love You";
" ^! {' q3 s+ g* O. w% d( l fwire(x, 6,12,fp);//写入6*12=72字节</P>- l9 m, @; B5 j5 `6 T: ]% x
<P> 将把"I Love"写到流fp中12次,共72字节</P>
/ o, K9 k0 k) l2 u* z<P>15.tmpfile()
# T8 p% U- }5 q: u" U; K9 n9 { 其原型是FILE *tmpfile(void); 生成一个临时文件,以"w+b"的模式打开,并返回这个临时流的指针,如果失败返回NULL。在程序结束时,这个文件会被自动删除。</P>& X4 @# Y4 a' H; K4 g* s
<P>例:FILE *fp=tmpfile();</P>
1 |/ Z1 c$ ^- |2 @$ A8 m- S<P>16.tmpnam();
9 Y2 ~* Z3 f* X. ~ 其原型为char *tmpnam(char *s); 生成一个唯一的文件名,其实tmpfile()就调用了此函数,参数s用来保存得到的文件名,并返回这个指针,如果失败,返回NULL。</P>
+ q: |5 x2 S2 Y9 b% n4 v, A- P b) g4 c U
<P>5 I; j4 n2 k- F
</P> |
zan
|