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

我的地盘我做主
该用户从未签到
 |
< >、基于C的文件操作 * O) I1 ` q# T* E: R- P# v& h% g+ w
在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之。</P>* P" r4 P6 `8 D
< >一、流式文件操作
* j. Z7 S7 O+ d* T3 z 这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下:</P>
8 O4 Q$ k# U& {+ e( y- \< >typedef struct {
. J+ r* y/ i9 _0 u' P8 Vint level; /* fill/empty level of buffer */( z, O4 b i6 i5 q) L; c8 O
unsigned flags; /* File status flags */9 r, n+ |' W( ~4 y4 P7 _6 `5 H
char fd; /* File descriptor */
% `+ j* P9 t w# G& g+ Runsigned char hold; /* Ungetc char if no buffer */8 M/ K5 l3 |$ }( M1 c, u* {. U
int bsize; /* Buffer size */
" z. ?- l( f. A- yunsigned char _FAR *buffer; /* Data transfer buffer */3 R1 _( C3 j) |6 k5 K% P
unsigned char _FAR *curp; /* Current active pointer */
2 x, w1 C- d2 S; b9 g% aunsigned istemp; /* Temporary file indicator */, c* V, Z9 y1 Z# T# }' Y" d" o. b
short token; /* Used for validity checking */
; T8 s. Q3 }, N) t" D4 J$ Z} FILE; /* This is the FILE object */</P>
( b$ L1 Q& U9 d) `4 w [< > FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行,此种文件操作常用的函数见下表 函数 功能 * h# s7 L" Q0 g/ H
fopen() 打开流
" ~5 E9 j$ G2 o/ f+ Ofclose() 关闭流
8 v9 p+ d/ S8 r2 @fputc() 写一个字符到流中 ; e/ k! ?: k9 x1 ?& V$ `
fgetc() 从流中读一个字符 8 N/ o; |6 x9 _! l( A5 ^+ Q9 X
fseek() 在流中定位到指定的字符 - I: N" m2 u' S* }3 j% [) w
fputs() 写字符串到流 * f$ L5 d& d7 v- Q; m: ^; h
fgets() 从流中读一行或指定个字符
4 b. M7 ]9 [: Yfprintf() 按格式输出到流 9 V& C( P8 f/ n. i) k* v4 m
fscanf() 从流中按格式读取
# ~ j- v; {5 r5 [& y! N3 yfeof() 到达文件尾时返回真值 ! {; E1 |0 `" J5 e7 C
ferror() 发生错误时返回其值
7 j1 B- h6 c# F2 Q8 prewind() 复位文件定位器到文件开始处 2 x+ Z- Q# b9 u1 P- i/ r; b, \4 ~3 i
remove() 删除文件
9 M/ J# ]9 N' e( @. U8 Qfread() 从流中读指定个数的字符 } B6 {3 p! r( L1 B+ v& j O; K
fwrite() 向流中写指定个数的字符 ' A d5 ?) y5 Q* a ~1 |( r
tmpfile() 生成一个临时文件流
; D1 T, ~( \$ O* x7 h S# I+ \8 Ktmpnam() 生成一个唯一的文件名 </P>
8 j! F. r- L. C< >
, g C( c& {+ r. T2 P' B( ^7 ^ 下面就介绍一下这些函数</P>
; f% p& \5 I$ m1 B< >1.fopen()
9 c P: [1 F$ y P+ }2 H1 V7 q fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能</P>
N* X8 [3 Q3 F< >为使用而打开一个流 0 K- T0 q8 p& U6 \4 l0 p
把一个文件和此流相连接 p3 M/ P* O7 z/ w
给此流返回一个FILR指针: t/ |% Q5 A" F- D4 |$ U x, y
参数filename指向要打开的文件名,mode表示打开状态的字符串,其取值如下表</P>
7 @: x7 W# U# B( i9 V b; B' ?3 @; v< >字符串 含义 & S" o1 v7 w9 t* y
"r" 以只读方式打开文件 K, l8 S6 O; ?, X9 b7 I8 }0 \& b
"w" 以只写方式打开文件 9 I5 {+ |* C% a r. f0 p. f
"a" 以追加方式打开文件 / g- S/ _ I/ K- T8 ^
"r+" 以读/写方式打开文件,如无文件出错
0 A7 r# J S5 m9 [1 q4 s0 f- N"w+" 以读/写方式打开文件,如无文件生成新文件 </P>
! `' J( ?$ v. E3 r< > 一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符'\n',而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。</P>
) S, n) `1 d! d# S" H< > 系统默认的是以文本模式打开,可以修改全部变量_fmode的值来修改这个设置,例如_fmode=O_TEXT;就设置默认打开方式为文本模式;而_fmode=O_BINARY;则设置默认打开方式是二进制模式。</P>
6 t0 A4 v3 s8 e: |# i+ ~< > 我们也可以在模式字符串中指定打开的模式,如"rb"表示以二进制模式打开只读文件,"w+t"或"wt+"表示以文本模式打开读/写文件。</P>
" D- V9 S; i3 p. `+ ]< > 此函数返回一个FILE指针,所以申明一个FILE指针后不用初始化,而是用fopen()来返回一个指针并与一个特定的文件相连,如果成败,返回NULL。</P>
5 j$ c$ h% ~# V- o7 O' B< >例:</P>. H h0 h2 c5 o; e5 _$ I# U7 ~! k5 v
< > FILE *fp; : Z# @% q) ^) J2 b7 Z6 I. i- H2 m
if(fp=fopen("123.456","wb"))3 I4 ]2 ~3 b$ g0 b) M
puts("打开文件成功");& j6 `) p0 s4 Y" R$ W
else 0 o$ g: I# X# p, a9 f* {- U5 {; i% j4 f
puts("打开文件成败"); </P>
! ~8 x; I' E( b: c< >2.fclose()
$ Q9 V2 ^; l; r+ W, i9 b1 W. Y fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。</P>! B1 o3 l; f* C) S. k5 M& `
< > 在程序结束时一定要记得关闭打开的文件,不然可能会造成数据丢失的情况,我以前就经常犯这样的毛病。</P>
( z; W/ ~' G" s j$ `5 j. l1 z! A& ]< >例:fclose(fp);</P>6 X% z' m' x( k0 G
< >3.fputc()$ |6 b' @; H. [: f0 R t( U4 {
向流写一个字符,原型是int fputc(int c, FILE *stream); 成功返回这个字符,失败返回EOF。</P>
1 ^) Y1 {) s" [3 n3 J2 j< >例:fputc('X',fp);</P>* C* ?/ Y9 n" i4 L( [( { M, z: j, r
< >4.fgetc()( o0 `; Y3 L" f" ~8 ^
从流中读一个字符,原型是int fputc(FILE *stream); 成功返回这个字符,失败返回EOF。</P>+ M$ O: \ C; F, x. X
< >例:char ch1=fgetc(fp);</P>! R: |2 n% Y+ h# k
< >5. fseek()& f {6 u5 `" _4 d) u
此函数一般用于二进制模式打开的文件中,功能是定位到流中指定的位置,原型是int fseek(FILE *stream, long offset, int whence);如果成功返回0,参数offset是移动的字符数,whence是移动的基准,取值是</P>+ m. B5 l. o" C( A& Z9 c
< >符号常量 值 基准位置
1 j' w) q6 d7 `8 X# P3 nSEEK_SET 0 文件开头
( D% r- J7 a7 `/ _# SSEEK_CUR 1 当前读写的位置 0 Z; v! { r; \+ e7 _
SEEK_END 2 文件尾部 </P>
- c Z# Z7 q7 ?# d7 p m/ ^3 r< >例:fseek(fp,1234L,SEEK_CUR);//把读写位置从当前位置向后移动1234字节(L后缀表示长整数)</P>
1 N I: t6 ?$ r; w% l! C0 {' l< > fseek(fp,0L,2);//把读写位置移动到文件尾</P>
( V8 C; O4 ~+ C7 Z7 d3 Z# r< >6.fputs()
) C, g) g7 q4 t, x9 M( G; h 写一个字符串到流中,原型int fputs(const char *s, FILE *stream); </P>2 ] z5 |: I) g$ Z
< >例:fputs("I Love You",fp);</P>$ T) h3 g+ W- k' \- T- A
< >7.fgets() H9 v9 F8 [0 v8 Y! D7 ]& R# o
从流中读一行或指定个字符,原型是char *fgets(char *s, int n, FILE *stream); 从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s的指针,否则返回NULL。</P>0 q- m+ P) i+ }1 d& p. O
< >例:如果一个文件的当前位置的文本如下</P>
4 d1 f5 v2 E n4 S m< >Love ,I Have</P>3 x& u3 x5 v5 B6 b0 g# j
<P>But ........</P>
' s" S& k0 q: Y6 e5 }<P>如果用</P>0 _0 D+ i& G& a- o9 t+ w
<P> fgets(str1,4,file1);</P>
: ]4 Q, s- D' A6 J7 M* Z. \<P>则执行后str1="Lov",读取了4-1=3个字符,而如果用</P>
% H; ^, O. r1 h. o$ m# \# W, b<P> fgets(str1,23,file1);</P>
. R! j( V, v2 v<P>则执行str="Love ,I Have",读取了一行(不包括行尾的'\n')。</P>
/ t8 Q; C% K* q# x% ^: X<P>8.fprintf()
: w- z$ N+ ]/ y/ o( m1 O 按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了</P>) ]% |) M, o1 g ^$ A% [2 D
<P>例:fprintf(fp,"%2d%s",4,"Hahaha");</P>
& h9 t2 ]/ g, }5 i5 C% ?<P>9.fscanf()
: e, d: v8 r. t" U 从流中按格式读取,其原型是int fscanf(FILE *stream, const char *format[, address, ...]);其用法和scanf()相同,不过不是从控制台读取,而是从流读取罢了。</P>
: v0 V/ A1 M o; L# ?& I<P>例:fscanf(fp,"%d%d" ,&x,&y);</P>$ X+ X6 L3 c# p7 j3 o& B5 g
<P>10.feof()
/ M3 K. e) ?& C) d 检测是否已到文件尾,是返回真,否则返回0,其原型是int feof(FILE *stream);</P>9 o1 y! @) q g$ h2 G m0 n* Y' a
<P>例:if(feof(fp))printf("已到文件尾");</P>
& M. [; b) ~0 r; G. f) o<P>11.ferror()% S* A: w" U% [7 I2 C+ `& g. c
原型是int ferror(FILE *stream);返回流最近的错误代码,可用clearerr()来清除它,clearerr()的原型是void clearerr(FILE *stream);</P>
& A/ B- u/ c* {* z1 ?, c: }/ D/ c9 _<P>例:printf("%d",ferror(fp));</P>% y' {8 [' k$ c" C* `+ f
<P>12.rewind()
# n! \; D0 m4 A 把当前的读写位置回到文件开始,原型是void rewind(FILE *stream);其实本函数相当于fseek(fp,0L,SEEK_SET);</P>, [8 o- w9 v4 z3 r
<P>例:rewind(fp);</P>
1 a1 s' w( @. [% ]; P+ X<P>12.remove()5 d) I6 J1 E; _/ v2 T
删除文件,原型是int remove(const char *filename); 参数就是要删除的文件名,成功返回0。</P>
9 ~& e0 t: _/ y5 O<P>例:remove("c:\\io.sys");</P>' S4 h8 W% E0 n7 R Z+ ~
<P>13.fread()6 d) ]* o/ D6 r7 R* x
从流中读指定个数的字符,原型是size_t fread(void *ptr, size_t size, size_t n, FILE *stream);参数ptr是保存读取的数据,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是读取的块数,如果成功,返回实际读取的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>! G' O6 r3 N' ]' H% D9 f
<P>例:</P>. w- ~3 f3 ^1 d
<P> char x[4230];
7 u% E4 a" F2 h6 @9 t! V4 L FILE *file1=fopen("c:\\msdos.sys","r");
4 Y/ T" ^" `8 O& ~8 _3 _8 p fread(x,200,12 ,file1);//共读取200*12=2400个字节</P>) u: ^2 A }9 D! [) ^6 k s- b
<P>14.fwrite()5 I7 x3 B1 ~3 z; b3 y- q8 `
与fread对应,向流中写指定的数据,原型是size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);参数ptr是要写入的数据指针,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是要写的块数,如果成功,返回实际写入的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>
, R/ l! Z! Z2 c3 C0 U! |# y- E4 _<P>例:</P>2 c5 ~0 A' H' {( j6 |7 {0 B
<P> char x[]="I Love You";
4 d4 X+ \/ j5 f; K, w8 H) n0 m fwire(x, 6,12,fp);//写入6*12=72字节</P>
/ U) e+ @% g- }7 s<P> 将把"I Love"写到流fp中12次,共72字节</P>* |8 _3 Z/ H; n D" B
<P>15.tmpfile()
) n& K7 N0 X" }0 R7 o7 l5 l6 B 其原型是FILE *tmpfile(void); 生成一个临时文件,以"w+b"的模式打开,并返回这个临时流的指针,如果失败返回NULL。在程序结束时,这个文件会被自动删除。</P>) @ R8 H1 d" D
<P>例:FILE *fp=tmpfile();</P>
5 V$ \, E# a- K<P>16.tmpnam();
* p9 e; G1 c, _9 D; @" H% _4 w- e 其原型为char *tmpnam(char *s); 生成一个唯一的文件名,其实tmpfile()就调用了此函数,参数s用来保存得到的文件名,并返回这个指针,如果失败,返回NULL。</P>
* d, ?6 F# M2 h5 W3 H" ~+ R7 m! Y; }; Z X7 a/ s' X
<P>
/ K4 ~) B1 g3 j1 k I </P> |
zan
|