|
|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
×
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;. J& T% V+ V% D, {- F$ ?) J
9 B* m3 d6 I( _8 l% E5 x2 D
在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:
8 B. _* M: I1 G, H/ c8 x: K8 X* L, e) D , X7 a, B0 ]6 y# |0 _
1、插入器(<<)
# C. ]4 }; X1 o , ]" A' Z9 m( N+ K
向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。
! k( ^; A; p* z p d6 v+ I: G 4 [* |& ~8 P# \# C
2、析取器(>>)# d/ s3 j9 V4 ]( q; l
7 k( X7 ^3 c" ~0 e
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。
5 k, t& P9 j4 i' J( M1 u8 j
8 s/ ]% `$ I% \" G 在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。
* i* ~! b/ A6 A7 n2 j/ i& d
( {" ^6 q. |7 H8 H+ S 一、打开文件) O J& t; z. Z, U# z9 M& c6 o
6 V3 s% L! M) G1 A/ ^! Q
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:2 `/ F, f3 t5 Z+ _- S% I: v7 S( E( Z$ q
6 R1 f, t7 K8 r6 _0 p6 K& J) u, ^* A3 q
void open(const char* filename,int mode,int access);参数:8 ~/ l& n9 t3 Z, B4 r2 k
* g4 t+ ?6 ~- S) L( R. w filename: 要打开的文件名" n# \: N2 b& r- O" @
2 ]- r# Y- P# _& c+ G, M0 M
mode: 要打开文件的方式
) J, v4 A2 [& v. H* x. o- X ( l; V8 h, s8 {8 J% i) B
access: 打开文件的属性, @. H/ a( u% E3 u' E
" O3 p1 X) S' q2 C' }
打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:+ j# ^" T& w9 ^9 D% G
4 R$ \2 M! w0 Z) b' n9 A/ E
ios::app: 以追加的方式打开文件
* _' C0 c+ v% [1 N' I+ S0 U/ T: R! q/ P
: T3 S" L/ h1 Y" a3 ~/ m: d0 P ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性& i/ r' I; ~9 F4 ^( R
$ r% ?" S9 |) T/ `2 X# ?4 {9 s ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文
6 T5 m) g- Z) K, \" @ # |4 i8 M- f6 g! }/ C0 j* ]
ios::in: 文件以输入方式打开(文件数据输入到内存)5 t& H9 Z8 Y8 a7 B7 }+ @& L1 `+ C( T
7 f: t9 ^6 P2 ?) I7 `
ios::out: 文件以输出方式打开(内存数据输出到文件)
+ j: m# m* p, X) y2 ^. k
5 [/ }( S6 a4 P& I7 s; L ios::nocreate: 不建立文件,所以文件不存在时打开失败3 H0 r' R, |) q' e5 b
& m2 D1 T( T8 J. ]8 `
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败6 A, p/ L7 q+ B( p3 w% k) E
7 i3 B: a3 Y4 z/ [
ios::trunc: 如果文件存在,把文件长度设为0$ N. ` m% h% x, @7 N; A* l
8 ~5 R& T) V3 c3 a* e" v
可以用“或”把以上属性连接起来,如ios::out|ios::binary1 \7 m/ z6 M" q9 c; D8 U; }
5 T( P( y. c: [ 打开文件的属性取值是:5 |- b) b* t: X+ J9 B% |$ }( q0 o0 x
$ ]' F$ g/ x! e1 \0 H 0:普通文件,打开访问 D& d1 H7 ^! E3 F- y$ i4 l3 q
0 }, r6 j7 j8 j Y! w# J# g6 g 1:只读文件
9 F8 R" M: B! g
6 y; F! Y% {) } { 2:隐含文件" p9 f! o2 u4 d
% A7 u3 P" G% f1 @% w$ C
4:系统文件) @9 ]" k5 U ^6 J" j* \- C
# e$ N' |+ F; X6 X9 P+ L. z
可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。
6 r) Q) q' e% t- ?: D2 _9 k5 }% ?
: f1 U: l7 _ S* r% k 例如:以二进制输入方式打开文件c:\config.sys
/ v1 `5 i5 q, A" h: {( {- O 5 \/ B Z" T9 U0 H A' U/ U
fstream file1;8 K( E( P6 {+ f9 w7 p$ ~" m% m- V) N3 _, B
& M8 g1 @7 ~/ _' u. l9 \& D
file1.open("c:\\config.sys",ios::binary|ios::in,0);
3 P- c8 K( p, b$ F1 s x/ r! O
2 Y3 h8 P8 T; \. K5 ? 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:: p- x9 _$ O/ }7 |
3 H4 J) e+ \0 X" s; {. E# n
file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);$ W, m) ]/ {/ ~" C' b+ s
+ W" D+ P! K C* I4 R
另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:: B. r; Q8 z, T& | V9 c
9 \3 W4 v) e. Y, _
fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。# F: g* e$ S4 [5 m
; ~; v* n! W8 `) ^0 ^3 A5 W
ifstream file2("c:\\pdos.def");//以输入方式打开文件
" U% B; U/ H4 @/ u8 `* V
f6 T" }( M; g/ o1 W0 s: |% l5 n ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。: D; o6 m+ G- \6 T0 z; r
1 \0 R6 {# g9 d
二、关闭文件: }% l% w' u; K" r) q6 }8 y! j
- J$ v( f# r% L( l) t
打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。
( ]0 D; x6 P. q: O! s8 }/ ] r) N- e 7 E* \1 @9 [5 A, L, x7 j/ z, ~
三、读写文件4 i3 P( v- A& F& _" s6 w
* {: e6 q" o$ c) y9 o% T 读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式7 X% L+ \" ^8 I& f; i
0 c) @* Z2 g7 ?" J! h! D! @
1、文本文件的读写
/ C' o! l! ~. _7 B # I: c; j: J3 n- ?8 L
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:
! E1 b& k' U8 B( G7 u# C 1 l3 Q1 Y) j; d' J
file2<<"I Love You";//向文件写入字符串"I Love You"2 u @( \$ S5 q: j) y, z
' H+ p- l3 _, T% O" \+ p. h int i;4 Q, u8 R8 \9 E- D% _
. v* P3 d* ^) U' q( _
file1>>i;//从文件输入一个整数值。7 t& U: C6 C, p$ P9 D6 F/ ~
" b' z1 G8 A4 n7 M& Z0 r0 @! v 这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
$ r* P! T. I8 n3 c7 z 3 ?+ p/ q% a* u, `9 r* B9 C
操纵符 功能 输入/输出
& l* _- P2 o7 d8 S( \ 8 d/ W6 j0 [7 x
dec 格式化为十进制数值数据 输入和输出$ B2 f0 G' C, F# Z; s
! V0 `" b% B( q
endl 输出一个换行符并刷新此流 输出5 Q3 E" b7 S8 \% v+ t7 U- @
! V+ v. a' B" K8 o, }
ends 输出一个空字符 输出
' E ~. i7 [% ?7 m
7 k' e% G( R7 L& [/ q+ N, |6 ~ hex 格式化为十六进制数值数据 输入和输出
, P9 p" g D+ S2 i & j6 u1 i3 h" n
oct 格式化为八进制数值数据 输入和输出% R% r! b8 b. Y/ ^! H
) ^0 X3 Q% `7 Z8 ~- c- r) |- s
setpxecision(int p) 设置浮点数的精度位数 输出1 i2 |1 w0 D/ v9 n' r4 {
6 x) k1 S. y4 {( ?; r! F 比如要把123当作十六进制输出:file1<
# t/ W7 s. C L, d d 2、二进制文件的读写/ q9 A3 f2 L4 j: V0 ]
6 ] ?$ A# l8 w v( m$ x" s
①put()
1 L* `2 @# l/ n* z; f% s + A8 B' q( E& _: j/ j2 v+ d+ w
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
! e' s0 r5 F: ?! c2 f! b5 N 7 I1 v: x3 Q. I9 d
②get()
8 H% a2 Y2 @# b: ~2 Q4 D 7 \( Y- O- ^4 R) |9 V X
get()函数比较灵活,有3种常用的重载形式:
# W; H N: I0 a0 I. ? 4 R$ J$ @5 S1 O1 D8 C
一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
4 `' f; b( g3 S1 [, q" X ( b% ?. c0 h. Z! ?" Z5 X+ T; u" d M. i5 x
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
$ W- {# V1 t2 V( i! B3 N2 g) p2 M 2 O; x& O4 n5 b0 i3 S- l' C
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:
: f& s) I9 U& H0 b3 S8 U & i. o- @0 i1 C
file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。
( C1 n+ g5 A: s! w; }3 b+ r & U+ ?9 a* H# L& S) I- U4 o
③读写数据块3 V0 Q3 n) w* d7 p2 K
+ G" y6 L* Z k. S: i% J/ s' D T
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:
) T$ u# F) |( Z& d) o P1 d ? / ~" Z+ e0 W0 s! v# { c' {1 Q
read(unsigned char *buf,int num);
2 {* |. X$ |% _" {: Z0 q& j! k ! u3 s) |) s& E, w2 Q
write(const unsigned char *buf,int num);) P/ w) J* U0 y% r4 Z
5 g- [" s9 d" m6 }/ H read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。* y; o, L/ J" L8 a' i- ^
) A. }4 s( z& ?3 w 例:
) S7 j, r1 b" O% ~: u
' `# {' g1 T A" o unsigned char str1[]="I Love You";7 D# [; T7 e' ~% [
" p3 S2 P4 x+ W/ A8 C int n[5];
. w- U; y3 o3 x g
3 p/ E5 l8 d6 m: k ifstream in("xxx.xxx");
+ B' o- a- M1 t3 Y
+ t& b% l: {+ s) h* T ofstream out("yyy.yyy");
& U- Z% ]7 c1 F
$ ?: u8 Y$ S3 l; p/ ?* I out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中9 p* z3 z5 {7 [! l
4 p& t+ W5 X- f$ k" p in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
, _1 x+ t) ?* ?' O: i 1 C' K& V' E* Z. L
in.close();out.close(); 四、检测EOF z3 O, E% ^: R
( i! S" X3 K! _$ x 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof(); Z$ L# o# ^7 ]# u5 O4 X: C' C
7 u! T* @' n; o 例: if(in.eof()) ShowMessage("已经到达文件尾!"); B; ?/ A3 D' J0 q7 P
3 G% ^: K" b: `: Y3 x 五、文件定位 Z* _' Y" P/ b; ^6 j1 P8 e( {
! B8 G; q8 k! Q/ ?& y
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
6 ^2 H" k: `' d- |' {- x ' w+ K5 |/ P( }, E: }0 _( m% D# f9 c
istream &seekg(streamoff offset,seek_dir origin);
) p1 F" b. K2 C* C- N* ~9 x% o- y Q 2 ~1 w/ d. k7 P. Y
ostream &seekp(streamoff offset,seek_dir origin);
/ v( ^( w! _$ U# ?3 M: m1 r 0 s5 K( E4 Q; ^( |
streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:/ b+ D1 Q f/ d. ^1 |
: {1 `/ Z; k* K; e$ w$ x" q
ios::beg: 文件开头
6 _. x9 o8 T0 X, T$ y. N
9 g4 R6 Y G4 R; v' X% ^7 h7 _6 T ios::cur: 文件当前位置" r% c# k+ P8 S4 a5 y
& t* C1 z) ` r; w ios::end: 文件结尾
) B- h: a+ X3 T$ o
" \. m- m7 a* }+ x6 V7 c) ] 这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:1 |* ?( l' b4 i6 @2 w' ], g* o# h- x
9 `- n; X3 F g8 Y4 f- w2 l file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节! N+ ]. d7 _3 l6 K" E- {& i( Y. N
8 F1 G8 I7 c0 T, ]. O* D
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
& t5 p- ^& ]5 q1 f0 b, }
' E0 y. n% h1 |$ j8 H+ B @ |
|