数学建模社区-数学中国

标题: borland c++ bulder的文件操作总结-3 [打印本页]

作者: 韩冰    时间: 2005-1-26 13:09
标题: borland c++ bulder的文件操作总结-3
<>在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:</P>+ s) G3 y5 x2 W4 U8 h
<>1、插入器(&lt;&lt;)# u  j+ W9 V4 K# R/ F8 W2 @
  向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout&lt;&lt;"Write Stdout"&lt;&lt;'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。</P>
3 T- N" f* l" Y+ ?/ ^/ y<>2、析取器(&gt;&gt;)+ K. B7 ?/ x2 v6 ~5 F2 |
  从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin&gt;&gt;x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。</P>; U9 k, X$ \  j6 W# K1 B
<>  在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。</P>
+ J) H: p! k/ u& @5 E0 ^/ \<>一、打开文件& z  A  m$ ~- Z6 J9 E
  在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:</P>( C' d; ?) R8 k* e& e8 W. A1 b
<>void open(const char* filename,int mode,int access);</P>+ N' H8 I- o# I7 g  U1 F+ v0 z
<>参数:</P>
0 ~' F: S% r/ G<>filename:  要打开的文件名
# j  ]+ E4 t% Z5 c% L; Lmode:    要打开文件的方式
. T7 x  Y6 T1 W% ]4 _2 I# A7 V2 ~access:   打开文件的属性* j! U# Y: s. @5 u3 V8 B$ F
打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下: </P>
9 o% |, P! Q8 U' U! n<>ios::app:   以追加的方式打开文件 : }* q% b4 l' t' w7 ^$ }1 q
ios::ate:   文件打开后定位到文件尾,ios:app就包含有此属性
0 h% i1 n8 y8 hios::binary:  以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文 7 e9 ~2 m: s* n/ W
ios::in:    文件以输入方式打开 " Q5 R* P) ?. j' {2 J. [
ios:ut:   文件以输出方式打开 4 H2 M( b5 l& ^3 }+ y. s7 j, z. S7 a' |
ios::nocreate: 不建立文件,所以文件不存在时打开失败 
9 M; z; D5 c* [1 ?. V" h) E0 k+ D8 @ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
( C/ w& c/ s+ a5 Q4 D" \9 L  y8 D. dios::trunc:  如果文件存在,把文件长度设为0
8 b" ?) d1 f1 q; }1 F  可以用“或”把以上属性连接起来,如ios:ut|ios::binary</P>* k+ f# n" o9 B% G8 c. a
<>  打开文件的属性取值是:</P>
. p  F5 b( s5 T$ w2 ?/ D<>0:普通文件,打开访问
" @. D# b, r7 @# t: y1:只读文件
' Z. V* x" \5 \0 u. ?' L2:隐含文件
/ H1 m( h, p1 }6 X/ q" h* u3 H4:系统文件
  c, c; C5 Q* F9 r: ~" H# [  可以用“或”或者“+”把以上属性连接起来 ,如3或1|2就是以只读和隐含属性打开文件。</P>
8 t6 l; Y5 t, T6 C4 u0 ^  y<>  例如:以二进制输入方式打开文件c:\config.sys </P>
! x# C2 c6 @: j/ m! M- m! n" n- @+ R<>  fstream file1;9 \1 c7 W$ ]0 i! ^6 |
  file1.open("c:\\config.sys",ios::binary|ios::in,0);</P>
( t) \+ m) w: x<>  如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:</P>
% V0 U8 V3 D; E- g<>  file1.open("c:\\config.sys");&lt;=&gt;file1.open("c:\\config.sys",ios::in|ios:ut,0);</P>( ^3 N2 {- j5 d2 ^& h% o$ v( R
<>  另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:</P>- w* W' D  A( G& _
<>  fstream file1("c:\\config.sys");</P>
- i7 t% }5 [; |2 v: l<>  特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。</P>+ m& }: a: j* Z  O9 H' h2 G3 E
<>  ifstream file2("c:\\pdos.def");//以输入方式打开文件
: E9 f! b& ?5 `0 K9 y) C  ofstream file3("c:\\x.123");//以输出方式打开文件</P>0 z3 Z" A1 Z( {; Z
<>  所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。</P>/ N4 f: k9 a/ n2 _* F, M0 i
<>二、关闭文件
4 }! h: f5 `- ]4 z  打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。</P>  a  |  p% x. t  [' w
<>三、读写文件8 t3 t8 S+ S1 A
  读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式</P>5 A2 K$ V- z: x1 f3 b
<>  1、文本文件的读写) r8 a1 X( G; x6 A8 A/ Z/ b- h
  文本文件的读写很简单:用插入器(&lt;&lt;)向文件输出;用析取器(&gt;&gt;)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:</P>
0 O9 o* E, I8 S6 O: k4 J<>  file2&lt;&lt;"I Love You";//向文件写入字符串"I Love You"
  v/ O, ]# t, _+ @7 s, M% Y/ X* l  int i;- M( S4 F" J9 m- n
  file1&gt;&gt;i;//从文件输入一个整数值。 </P>) [* f8 t3 h0 k- k0 j
<>  这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些</P>
, X$ {6 F  B  f6 x5 R<>操纵符 功能 输入/输出 : F: B8 h* x* ]
dec 格式化为十进制数值数据 输入和输出
2 g3 F4 s; U; y& w1 z7 E1 Zendl 输出一个换行符并刷新此流 输出
7 q$ [" V# d$ s3 [  F% K' A* k, zends 输出一个空字符 输出
. A* b0 [: i( w+ i! |hex 格式化为十六进制数值数据 输入和输出
* ?0 t7 y4 H3 Woct 格式化为八进制数值数据 输入和输出 * ?+ }3 @3 o  {6 @* X
setpxecision(int p) 设置浮点数的精度位数 输出 </P>
8 r* ?: N3 }- c. V0 h! @* y; S) E+ V<>  比如要把123当作十六进制输出:file1&lt;&lt;hex&lt;&lt;123;要把3.1415926以5位精度输出:file1&lt;&lt;setpxecision(5)&lt;&lt;3.1415926。</P>2 G0 ]0 C7 ^* K5 C4 z1 R$ A% C
<>  2、二进制文件的读写. ~5 N: T1 R! J6 T0 s
①put()% i" @; ?' _( C0 d
  put()函数向流写入一个字符,其原型是ofstream &amp;put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。 </P>
) `* R+ e1 g% d+ ~( z1 {6 ^4 f<>②get()
5 |6 A+ @: P; P2 G3 c  get()函数比较灵活,有3种常用的重载形式:</P>$ [2 t) `  G0 t& @6 Y6 d  N4 [
<>  一种就是和put()对应的形式:ifstream &amp;get(char &amp;ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。</P>
8 t  h1 @) l# p3 ?8 s& |8 ^+ ^<P>  另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。</P>/ C6 ]6 E8 }& W
<P>  还有一种形式的原型是:ifstream &amp;get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:</P>
7 Y, a' [7 x' s/ p) N( q<P>  file2.get(str1,127,'A');//从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。</P>, e* q: o0 q, u9 Y+ P" x
<P>③读写数据块
" Q( ?" r: y) Y+ B4 Q1 ]+ M6 B% B  要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:</P>( f4 I5 u' m/ C% i
<P>    read(unsigned char *buf,int num);$ O: K7 W0 j1 [8 f: f, L, J
    write(const unsigned char *buf,int num);</P>5 A: i" E* X) R: M) [, y
<P>  read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。</P>; d, |$ ~) ]/ a9 q' V3 G2 J: H) g
<P>例:</P>  L8 O3 v7 Z  b! o1 g
<P>    unsigned char str1[]="I Love You";
7 D; ^, d# \+ V4 x1 f+ |    int n[5];6 l. Y* G; s- V1 r; `
    ifstream in("xxx.xxx");
" X: J" p* ]/ S. E1 n    ofstream out("yyy.yyy");+ x7 s& W0 q( Z  \# ?3 z
    out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
# Q- z& [+ Q- E, |5 H) K    in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换$ g$ x* p" p. ?" k
    in.close();out.close(); </P>
. h; K! q: O1 w6 T$ \1 _  h$ u3 [, i<P>四、检测EOF
" U  M- B8 P# M1 ]1 b# j  成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();</P>
4 K7 U9 ]2 ], B; k2 ~<P>例:  if(in.eof())ShowMessage("已经到达文件尾!");</P>
# h$ R6 y) H: {  d0 c) S$ W<P>五、文件定位3 N" H( f0 y4 G
  和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是 seekg()和 seekp(),seekg()是设置读位置,seekp是设置写位置。它们最通用的形式如下:</P>4 f. P; m# P! z) d9 B4 K
<P>    istream &amp;seekg(streamoff offset,seek_dir origin);& t$ k! t. q1 n7 i
    ostream &amp;seekp(streamoff offset,seek_dir origin); </P>1 ]6 a+ s' o: U3 O
<P>  streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举: </P>; s8 X7 s& S8 n. ~! r+ M5 P
<P>ios::beg:  文件开头
3 n. i/ }. l: S( ?! G0 ?ios::cur:  文件当前位置 5 a# ?9 [) h* a/ n: A! n
ios::end:  文件结尾 6 b# ?6 [5 d' H& x3 `" c
  这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。</P>' z) `1 {: h: a) X) ~8 ~  k: ~  ]( q5 i
<P>例:</P>
, D; J9 L  [6 R, S; ?& Z+ s0 G<P>     file1.seekg(1234,ios::cur);//把文件的读指针从当前位置向后移1234个字节
) U5 K8 _) C( f. C  L     file2.seekp(1234,ios::beg);//把文件的写指针从文件开头向后移1234个字节 </P>
& U( Q. B6 g0 \<P>
- `, Y% |; ^1 o+ a</P>




欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5