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

我的地盘我做主
该用户从未签到
 |
< >、基于C的文件操作
- S% x( p" H# z) P$ e 在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之。</P>& W# x6 E& s" @# ]9 [5 g: w F
< >一、流式文件操作
: L. w0 e: u( U. @" v9 V 这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下:</P>; c" x5 a2 V- I, i% P
< >typedef struct {
2 S3 X" d# V( H6 M; _# u8 Pint level; /* fill/empty level of buffer */
, |/ E" q3 ~9 M- F, Xunsigned flags; /* File status flags */2 V6 M8 ~' f& r& X& s
char fd; /* File descriptor */( [2 O0 i; }4 U+ C2 G8 I N% |
unsigned char hold; /* Ungetc char if no buffer */( f: C# o5 g6 s, R, A+ i
int bsize; /* Buffer size */
- Z: ]* }! } ounsigned char _FAR *buffer; /* Data transfer buffer */9 L+ ] r: D5 N. L( N
unsigned char _FAR *curp; /* Current active pointer */
) O! N5 h% q) t+ o- zunsigned istemp; /* Temporary file indicator */3 R) M O: k8 c3 e
short token; /* Used for validity checking *// S, o* ?. e ^9 W4 v
} FILE; /* This is the FILE object */</P>5 ?+ Y. q& m" |1 ^
< > FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行,此种文件操作常用的函数见下表 函数 功能 5 h3 a( U c5 E+ Z7 b4 R! Y* s
fopen() 打开流 / {9 }" |* C5 S2 J$ `
fclose() 关闭流
! E; ^! q, y7 {, Sfputc() 写一个字符到流中 8 `% \$ a5 [( ]9 l: G
fgetc() 从流中读一个字符 ) L I/ ]' e' Y) P5 ^
fseek() 在流中定位到指定的字符
8 M; u. ~5 m+ B0 _fputs() 写字符串到流
$ I( ^' L8 ~! lfgets() 从流中读一行或指定个字符 / x3 A! f: w! b" K- U0 @
fprintf() 按格式输出到流 & c- Q9 N8 a# H' o
fscanf() 从流中按格式读取 8 t) S8 E6 @1 l+ D" E' y% a
feof() 到达文件尾时返回真值 . n7 |- A; G& M L7 J! [
ferror() 发生错误时返回其值
, A1 r3 h% W# i. [& i: n% c S4 R& prewind() 复位文件定位器到文件开始处 ( W2 V% j/ w) G
remove() 删除文件
( ?4 [6 b) D& m# Y7 G6 kfread() 从流中读指定个数的字符 , g* [$ U6 S& U% T% @" j
fwrite() 向流中写指定个数的字符
% f% N" Q% t- ]0 R* ?tmpfile() 生成一个临时文件流 3 i3 M3 m- n! L% R
tmpnam() 生成一个唯一的文件名 </P>3 S% A& i6 ^7 n) r5 a
< >
+ Q9 A: C" q) k8 H* Y) H5 L 下面就介绍一下这些函数</P>
" v2 {6 v$ R2 P. x" P: W< >1.fopen()
! J% i$ }0 x H: O" I fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能</P>6 |4 c: E( ^5 j
< >为使用而打开一个流 4 d# T, L4 g4 E. T7 m
把一个文件和此流相连接 6 b1 q0 G0 D$ L7 |
给此流返回一个FILR指针1 k" W" X# ?" M5 h) ?
参数filename指向要打开的文件名,mode表示打开状态的字符串,其取值如下表</P>2 [: \) o, D: ]3 m9 W2 a
< >字符串 含义 / W+ a4 n, L# E; j+ A
"r" 以只读方式打开文件
6 y+ r3 F2 W/ F1 i- T) q- L: q* d"w" 以只写方式打开文件
9 K2 W. F8 G$ t- ]3 z"a" 以追加方式打开文件
; a+ R) Y, m z; f6 g9 i" I"r+" 以读/写方式打开文件,如无文件出错
4 k0 s" o. \/ h6 @$ |+ ?. `# G' {"w+" 以读/写方式打开文件,如无文件生成新文件 </P>' I7 ~) a! e* y' j2 w4 s$ V
< > 一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符'\n',而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。</P>
$ E+ c$ ~3 L" r0 M* J8 o& V< > 系统默认的是以文本模式打开,可以修改全部变量_fmode的值来修改这个设置,例如_fmode=O_TEXT;就设置默认打开方式为文本模式;而_fmode=O_BINARY;则设置默认打开方式是二进制模式。</P>1 `+ p- D5 U; r
< > 我们也可以在模式字符串中指定打开的模式,如"rb"表示以二进制模式打开只读文件,"w+t"或"wt+"表示以文本模式打开读/写文件。</P># q4 }$ ^5 ]6 x0 {
< > 此函数返回一个FILE指针,所以申明一个FILE指针后不用初始化,而是用fopen()来返回一个指针并与一个特定的文件相连,如果成败,返回NULL。</P>
! {- c0 h5 Q8 H4 P! ]$ j* {< >例:</P>
: _1 w; R' t+ R2 T* Z< > FILE *fp; E) {9 y: D" D: g0 j: C( v( a; h
if(fp=fopen("123.456","wb"))
" i( ^% M6 b3 k; I. D2 g puts("打开文件成功");; e/ D9 b5 [8 P
else 0 Z' _* |9 B# r; i F5 W
puts("打开文件成败"); </P>0 b4 {. ^6 g$ P1 U1 W0 H6 p; ^
< >2.fclose() 6 M, U( o) ~1 j0 ]5 R& I! ]
fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。</P>
0 G) R) p% ?+ [ k, f: [- G% {< > 在程序结束时一定要记得关闭打开的文件,不然可能会造成数据丢失的情况,我以前就经常犯这样的毛病。</P>
$ N# I+ j' v; i/ g J9 ]< >例:fclose(fp);</P># a& @, x) e* K2 n# P; ?9 r& E4 H
< >3.fputc()
. D$ b+ R. _, o! G, y 向流写一个字符,原型是int fputc(int c, FILE *stream); 成功返回这个字符,失败返回EOF。</P>. f H7 Z% U/ w8 }! z8 {2 @# q ?
< >例:fputc('X',fp);</P>
+ ^9 K$ n0 ^& {9 a1 r/ }7 x0 m- P< >4.fgetc()
* v( T2 ]$ d( I3 X( v) l: g+ N 从流中读一个字符,原型是int fputc(FILE *stream); 成功返回这个字符,失败返回EOF。</P>
" A. |# B) z1 x" {: c, G. h$ C< >例:char ch1=fgetc(fp);</P>
6 u3 f3 }: m$ X* }, v< >5. fseek()
& R: p; K- ]! ~( S/ P2 j 此函数一般用于二进制模式打开的文件中,功能是定位到流中指定的位置,原型是int fseek(FILE *stream, long offset, int whence);如果成功返回0,参数offset是移动的字符数,whence是移动的基准,取值是</P>& F* F4 Z. j0 q$ O, F% F( a1 e
< >符号常量 值 基准位置
# P) g8 R. c M# E2 Q6 j( |SEEK_SET 0 文件开头 9 P( M6 j( [) |2 ~, ^
SEEK_CUR 1 当前读写的位置
# A* Q- p3 o6 j! l# XSEEK_END 2 文件尾部 </P>
- D( V0 F5 p. r( u9 b& ^< >例:fseek(fp,1234L,SEEK_CUR);//把读写位置从当前位置向后移动1234字节(L后缀表示长整数)</P>& l+ I, Y* J" _
< > fseek(fp,0L,2);//把读写位置移动到文件尾</P>
+ x# k; X7 B& E5 C, W& T< >6.fputs()
X1 |4 e n/ D8 }( ` 写一个字符串到流中,原型int fputs(const char *s, FILE *stream); </P>3 Z: _: D# ?$ R' i5 S
< >例:fputs("I Love You",fp);</P>/ A- h3 o' ~1 T* ^2 V+ I
< >7.fgets()
) k L( m% ]+ [! {0 b- n; U6 p 从流中读一行或指定个字符,原型是char *fgets(char *s, int n, FILE *stream); 从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s的指针,否则返回NULL。</P> ]: z' R: c8 c
< >例:如果一个文件的当前位置的文本如下</P>* ], m! G2 J3 d) i
< >Love ,I Have</P>
# G9 i" g$ K! {: K0 s<P>But ........</P>
$ D) J% H \* a" k; \ b<P>如果用</P>
5 ]5 Q6 f3 K( `1 G, w9 g- i7 n9 T<P> fgets(str1,4,file1);</P># _0 ]9 I# g Z+ N
<P>则执行后str1="Lov",读取了4-1=3个字符,而如果用</P>
& _; Z/ [6 `/ B0 j<P> fgets(str1,23,file1);</P>- E; u7 h% c2 F2 b- L
<P>则执行str="Love ,I Have",读取了一行(不包括行尾的'\n')。</P>
. U d' t( \, @3 {7 \<P>8.fprintf() `% S' m4 d( o
按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了</P>
# u: X- {! M% ^<P>例:fprintf(fp,"%2d%s",4,"Hahaha");</P>9 c2 j- t [5 N- j: D+ H; I; G7 Q
<P>9.fscanf()
+ E' e( d3 P1 C# S 从流中按格式读取,其原型是int fscanf(FILE *stream, const char *format[, address, ...]);其用法和scanf()相同,不过不是从控制台读取,而是从流读取罢了。</P>1 c$ h; A; p, }7 {" W. A5 ^
<P>例:fscanf(fp,"%d%d" ,&x,&y);</P>4 X3 t# Y, r6 r, v# {9 E8 d
<P>10.feof()" E$ ?. `6 a4 d
检测是否已到文件尾,是返回真,否则返回0,其原型是int feof(FILE *stream);</P>
( y% _! ~9 M; S! ?# s! @5 B<P>例:if(feof(fp))printf("已到文件尾");</P>
9 e8 g! n4 H; V9 h8 e- l4 ~& n<P>11.ferror()
, o' k+ @4 G7 r7 ]1 R 原型是int ferror(FILE *stream);返回流最近的错误代码,可用clearerr()来清除它,clearerr()的原型是void clearerr(FILE *stream);</P>
" x3 Q5 X5 `& H8 a; U<P>例:printf("%d",ferror(fp));</P>
, f# K* N$ h1 | a* f$ z8 g r$ r<P>12.rewind(), h6 [! ? z% \: M3 A1 Q3 k3 e
把当前的读写位置回到文件开始,原型是void rewind(FILE *stream);其实本函数相当于fseek(fp,0L,SEEK_SET);</P>6 B, M, V% a( _9 y2 F/ m( i
<P>例:rewind(fp);</P>9 L! w) `- K, z
<P>12.remove()
6 ?- n Y! {3 K+ I 删除文件,原型是int remove(const char *filename); 参数就是要删除的文件名,成功返回0。</P># @# l8 P" D: `( O7 e& P/ b
<P>例:remove("c:\\io.sys");</P>
9 Z. w3 f0 T( H3 K<P>13.fread()7 u( l) E* h; k# c
从流中读指定个数的字符,原型是size_t fread(void *ptr, size_t size, size_t n, FILE *stream);参数ptr是保存读取的数据,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是读取的块数,如果成功,返回实际读取的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>
" i- x9 d% l9 Z- g" J1 k<P>例:</P>
1 K$ P3 T3 v' a; {8 L0 W! j<P> char x[4230]; E% F) k) G- ^8 M, }5 B3 j/ h
FILE *file1=fopen("c:\\msdos.sys","r");
( p* L" S0 ]- ?- y4 [ fread(x,200,12 ,file1);//共读取200*12=2400个字节</P>
3 p8 `+ Z( E' M. K3 k) A3 H<P>14.fwrite()
, x; ]3 Z& m5 W: ^ 与fread对应,向流中写指定的数据,原型是size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);参数ptr是要写入的数据指针,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是要写的块数,如果成功,返回实际写入的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>( j4 Y+ m; d9 ^4 b( R* t. w( A
<P>例:</P>
8 k6 S" C& Z- o3 F5 G8 m% i<P> char x[]="I Love You";
) p( t$ S5 K- b8 O$ K6 \- I. _ fwire(x, 6,12,fp);//写入6*12=72字节</P>
2 i3 \0 X! X+ w) s+ w" c7 z<P> 将把"I Love"写到流fp中12次,共72字节</P> P7 I" K9 |6 `" y9 F% B
<P>15.tmpfile()
) @" q# u0 F. P2 B } 其原型是FILE *tmpfile(void); 生成一个临时文件,以"w+b"的模式打开,并返回这个临时流的指针,如果失败返回NULL。在程序结束时,这个文件会被自动删除。</P>& P. |. }) S7 G2 {
<P>例:FILE *fp=tmpfile();</P>
! P6 w/ z8 y' O0 q; h: f5 ]<P>16.tmpnam();
( E+ W- l% F: W9 d7 s: L7 @; ^$ Z 其原型为char *tmpnam(char *s); 生成一个唯一的文件名,其实tmpfile()就调用了此函数,参数s用来保存得到的文件名,并返回这个指针,如果失败,返回NULL。</P>
/ N+ l y7 J6 M* W# G$ v: w5 b0 s
3 a: M. Z/ H6 T2 A<P>
: Z/ _- M8 C2 d& P$ {5 J4 K </P> |
zan
|