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

我的地盘我做主
该用户从未签到
 |
< >、基于C的文件操作
4 d" S. ?# k" Y7 e( x% d 在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之。</P>/ r# r& d% L6 n+ J
< >一、流式文件操作: q5 `1 A4 A( `( A- l) T" k
这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下:</P>
0 m$ @+ ~2 |7 \: H< >typedef struct {5 ~4 f, S* U# F4 w
int level; /* fill/empty level of buffer */
8 d! w- @, q& i0 L L' W Ounsigned flags; /* File status flags */+ z7 [* ^/ Y) v k
char fd; /* File descriptor */8 `2 Y& R) L1 I4 V* I6 q# c3 V. D, w
unsigned char hold; /* Ungetc char if no buffer */
. Q$ K% b$ E5 @int bsize; /* Buffer size */
1 Q# X+ E+ k( p* r' dunsigned char _FAR *buffer; /* Data transfer buffer */- P8 S6 K0 H. _9 O$ J! M$ I8 X' C" z
unsigned char _FAR *curp; /* Current active pointer */
- z, G( y$ v! {( x5 _3 o+ \unsigned istemp; /* Temporary file indicator */# P8 A9 y2 `* K7 p
short token; /* Used for validity checking */6 y# ]7 j/ K8 y' x- P% P; }
} FILE; /* This is the FILE object */</P>$ P1 T+ i# @( }+ h. p" }
< > FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行,此种文件操作常用的函数见下表 函数 功能
9 A$ U( Y' I# c+ jfopen() 打开流
3 m- [5 G5 D: V9 Z- Vfclose() 关闭流 # d l$ }2 O) J' B, h* `# {
fputc() 写一个字符到流中
3 B+ V( S( A' ~7 s! Yfgetc() 从流中读一个字符 - D' ]6 O$ Y0 A7 u' |
fseek() 在流中定位到指定的字符
: E) _- J0 v% A! Tfputs() 写字符串到流 r B( }8 L' B# U* y
fgets() 从流中读一行或指定个字符 & U7 R; }) y6 s. @& M& q/ Z1 P/ h
fprintf() 按格式输出到流
& m; t4 g4 ]( \' w6 Ifscanf() 从流中按格式读取 , V$ V# `+ G$ Q/ g' [. A, t
feof() 到达文件尾时返回真值 - U9 w+ W3 p+ g& g# `. b( P" s5 q
ferror() 发生错误时返回其值 1 b S$ a5 M8 T; O
rewind() 复位文件定位器到文件开始处
$ ~( \& z$ `5 f& E# Z7 Oremove() 删除文件 : q7 B) Y, L r; x
fread() 从流中读指定个数的字符 ' p3 g: `/ _3 R1 N, Z
fwrite() 向流中写指定个数的字符
& n2 i: v- x% E7 H" h6 D {tmpfile() 生成一个临时文件流 " p- ]8 \+ m# l4 q9 j
tmpnam() 生成一个唯一的文件名 </P>
+ Y r; y0 [2 |< >6 P5 D* f, F* B
下面就介绍一下这些函数</P>! G1 w5 Z4 ]2 z, N7 G. ]
< >1.fopen()
}6 N" ]$ A* v7 v fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能</P>
* {! c3 ^6 _9 L: |: h< >为使用而打开一个流
6 k8 T* ]6 Y; L! G. \把一个文件和此流相连接 6 W! |3 d) f" t
给此流返回一个FILR指针1 W9 V' W5 f, y
参数filename指向要打开的文件名,mode表示打开状态的字符串,其取值如下表</P>
0 p0 [4 B+ E2 O; w7 s7 o2 ]< >字符串 含义
5 k D2 l& x/ z' }"r" 以只读方式打开文件 , j+ A; ^* u; {; X' W
"w" 以只写方式打开文件
$ z: E! s) l. u( f! V- v"a" 以追加方式打开文件
! F0 S. j+ E% T7 C- h' M"r+" 以读/写方式打开文件,如无文件出错
1 p# k& ]- `$ F# o. P6 k"w+" 以读/写方式打开文件,如无文件生成新文件 </P>
% c) I" Q" k/ \5 Q* n1 S% k ]< > 一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符'\n',而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。</P>1 S" _+ E+ t- T- g5 W8 u8 @! T/ J2 g
< > 系统默认的是以文本模式打开,可以修改全部变量_fmode的值来修改这个设置,例如_fmode=O_TEXT;就设置默认打开方式为文本模式;而_fmode=O_BINARY;则设置默认打开方式是二进制模式。</P>7 X" q, ^$ q9 }/ r; ^# Y
< > 我们也可以在模式字符串中指定打开的模式,如"rb"表示以二进制模式打开只读文件,"w+t"或"wt+"表示以文本模式打开读/写文件。</P>' x" p/ t) ]: I- i' c; D1 \. k
< > 此函数返回一个FILE指针,所以申明一个FILE指针后不用初始化,而是用fopen()来返回一个指针并与一个特定的文件相连,如果成败,返回NULL。</P>% t' ]# ?0 w* j2 F
< >例:</P>
! {( a4 N" x9 q< > FILE *fp;
! D7 M/ ?! W/ l- q. b: B if(fp=fopen("123.456","wb"))
5 E3 [, E+ W; i s& r+ k puts("打开文件成功");
* x1 x& X; L# C# Q else
: T1 [4 G+ v* m: C* |# \ puts("打开文件成败"); </P>% ]$ r$ ~, y. k3 g
< >2.fclose() 3 o+ r+ G) n1 ~& {8 f. x# i6 u
fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。</P>
# n( S9 i* ?# o; s: a< > 在程序结束时一定要记得关闭打开的文件,不然可能会造成数据丢失的情况,我以前就经常犯这样的毛病。</P>
2 z* |1 R& e. G* X2 A% {5 r+ l. o< >例:fclose(fp);</P>
" R, s- E1 f. u8 `8 R6 I& m) \< >3.fputc()
8 L3 g" E8 d! X4 _2 m4 C& F9 }0 k 向流写一个字符,原型是int fputc(int c, FILE *stream); 成功返回这个字符,失败返回EOF。</P>
: y$ V* k! ]- U5 V5 y: f4 J< >例:fputc('X',fp);</P>
i8 c( h. _' W( b/ r1 C# }< >4.fgetc()
) ]7 `$ b$ e5 m* o4 W$ f$ W) U 从流中读一个字符,原型是int fputc(FILE *stream); 成功返回这个字符,失败返回EOF。</P>" s2 O2 L9 _" \$ O
< >例:char ch1=fgetc(fp);</P>
+ `; u% `7 z1 {9 G6 z< >5. fseek(): L/ b) {9 G' L
此函数一般用于二进制模式打开的文件中,功能是定位到流中指定的位置,原型是int fseek(FILE *stream, long offset, int whence);如果成功返回0,参数offset是移动的字符数,whence是移动的基准,取值是</P>% u5 {/ H4 k1 {( }
< >符号常量 值 基准位置 + J" ]' |% d( u- J7 w" N* z% ]( n
SEEK_SET 0 文件开头
2 J% {6 J% H- u6 b) _% uSEEK_CUR 1 当前读写的位置 * c W* O& \; h9 m& E5 a
SEEK_END 2 文件尾部 </P>
1 [: V9 F1 J. @1 X% ^+ F< >例:fseek(fp,1234L,SEEK_CUR);//把读写位置从当前位置向后移动1234字节(L后缀表示长整数)</P>
3 w( J |" Z2 {) m# @* A< > fseek(fp,0L,2);//把读写位置移动到文件尾</P>
( G( ?. ^; v: I) t/ E3 c! }< >6.fputs()0 E; R: s1 |! Q1 y
写一个字符串到流中,原型int fputs(const char *s, FILE *stream); </P>
' d3 g1 s6 Z& m) O; d7 X< >例:fputs("I Love You",fp);</P>
9 [3 ]9 A% D8 m% N \9 M< >7.fgets()+ X# S4 p* k; g) d5 n' B
从流中读一行或指定个字符,原型是char *fgets(char *s, int n, FILE *stream); 从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s的指针,否则返回NULL。</P>" S6 Z- T2 D: c U' F* k
< >例:如果一个文件的当前位置的文本如下</P>2 t7 Y8 X; K; Z% t# G u
< >Love ,I Have</P>- n# y" x7 `7 c8 o0 i, [
<P>But ........</P>
+ I5 g* E5 K9 [% n. d( t7 A- }<P>如果用</P>3 \& d6 ~* t$ \9 w" k7 n2 ~
<P> fgets(str1,4,file1);</P>
" i) u6 l( L6 ^' @<P>则执行后str1="Lov",读取了4-1=3个字符,而如果用</P>
5 r: n# {' c q1 ~3 S& q<P> fgets(str1,23,file1);</P>7 D7 ^5 t7 s- m( n# C/ x5 J: a( ?& ~
<P>则执行str="Love ,I Have",读取了一行(不包括行尾的'\n')。</P>9 B8 h' h! ]1 J0 E. M. ^. Q
<P>8.fprintf()
* d5 Z m6 S& a, B; ^1 m" F 按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了</P>
* a9 I+ ?! X, ]- Y1 ~1 u<P>例:fprintf(fp,"%2d%s",4,"Hahaha");</P>
( z& r( A9 O; L& d% A3 G1 b<P>9.fscanf()6 |% K6 r' n: X
从流中按格式读取,其原型是int fscanf(FILE *stream, const char *format[, address, ...]);其用法和scanf()相同,不过不是从控制台读取,而是从流读取罢了。</P>) @8 e$ M& t6 S- ?0 I' K
<P>例:fscanf(fp,"%d%d" ,&x,&y);</P>
+ v U2 ~/ H7 i$ ^<P>10.feof()
6 U/ Q+ C" g2 [ ~3 g 检测是否已到文件尾,是返回真,否则返回0,其原型是int feof(FILE *stream);</P>" h0 l+ i4 j. H( m0 @* @
<P>例:if(feof(fp))printf("已到文件尾");</P>
$ {8 a: k$ E1 y) {2 Z( T) ?7 u<P>11.ferror()( v; v. E" }8 ?% d; a% x
原型是int ferror(FILE *stream);返回流最近的错误代码,可用clearerr()来清除它,clearerr()的原型是void clearerr(FILE *stream);</P>6 C1 R6 T1 c" H/ G+ g
<P>例:printf("%d",ferror(fp));</P>. }* U8 y2 V7 Y- I
<P>12.rewind()/ L( D. ]# T8 S- v, p
把当前的读写位置回到文件开始,原型是void rewind(FILE *stream);其实本函数相当于fseek(fp,0L,SEEK_SET);</P>. @% T5 ~ H3 e* |2 x' a
<P>例:rewind(fp);</P>, X$ v" Q* P2 B
<P>12.remove()
9 N& q4 L; w. A6 L# U, N6 \ 删除文件,原型是int remove(const char *filename); 参数就是要删除的文件名,成功返回0。</P>
L7 h" N( l# r<P>例:remove("c:\\io.sys");</P>, t$ o8 _, f; R% Q- w
<P>13.fread()
2 s0 A @5 I' l& f+ C2 M 从流中读指定个数的字符,原型是size_t fread(void *ptr, size_t size, size_t n, FILE *stream);参数ptr是保存读取的数据,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是读取的块数,如果成功,返回实际读取的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>
- j/ K3 d0 p# h1 J' F<P>例:</P>* u) N, _* s( A. [: r% s3 N3 v# N
<P> char x[4230];& P. }0 e7 b" z+ t% l* Q: T2 V
FILE *file1=fopen("c:\\msdos.sys","r");$ D: A+ t! c* C1 W- S
fread(x,200,12 ,file1);//共读取200*12=2400个字节</P>" @2 F" q& v* G- c2 H2 l
<P>14.fwrite()
, S( U5 [2 ~. h 与fread对应,向流中写指定的数据,原型是size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);参数ptr是要写入的数据指针,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是要写的块数,如果成功,返回实际写入的块数(不是字节数),本函数一般用于二进制模式打开的文件中。</P>8 m9 j4 y+ o, k9 D6 I: _
<P>例:</P>
9 h9 @2 s+ |1 Y' U<P> char x[]="I Love You";9 Q6 H1 h: m* G |
fwire(x, 6,12,fp);//写入6*12=72字节</P>7 `8 q/ l- z% g2 K) g; J
<P> 将把"I Love"写到流fp中12次,共72字节</P>" f \- _5 |9 R& O
<P>15.tmpfile()1 l6 z0 z0 z- P. A
其原型是FILE *tmpfile(void); 生成一个临时文件,以"w+b"的模式打开,并返回这个临时流的指针,如果失败返回NULL。在程序结束时,这个文件会被自动删除。</P>
: }. {( l! \4 _) ^<P>例:FILE *fp=tmpfile();</P>
4 g0 M; K. s3 j) C- [% q<P>16.tmpnam();1 c# S, V; X& S, h/ q; Y- V9 b0 T3 e
其原型为char *tmpnam(char *s); 生成一个唯一的文件名,其实tmpfile()就调用了此函数,参数s用来保存得到的文件名,并返回这个指针,如果失败,返回NULL。</P>
. l8 V! U" z1 U( z# \- h
: u- t5 |% F* N/ l% \! p<P>
! Y' h0 M* D( l+ i+ i </P> |
zan
|