|
|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
×
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;# X) E4 `" B" r' g. O
! i& M4 P# b$ {* t( A4 c2 d 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:! r% v9 k2 x1 ]
* ^! O0 @( R! q3 L
1、插入器(<<)
$ i& j/ l, G9 h; y1 j3 T7 J- O ' k `' F2 M' ]6 A* a( U+ I# o) M" Q+ d
向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。
. o5 O3 g$ K1 g4 Z 0 t$ Z& c1 S5 J$ j, ^
2、析取器(>>)7 C! j( D' g5 ^" w
: m3 Y9 X8 ? _, ~- d
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。; O1 \% w0 m2 `$ s9 ?
. W8 R& [2 p1 c# k2 C# P
在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。
" L) r# B1 @9 U: u) X5 \ 8 s! U& m ~( y/ R5 B. Z1 {
一、打开文件! P! N) N* R; X5 D
! ~' r( _, b& _! h! e- E
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:( u% G$ s' _/ I
* j1 }1 ]* H. q8 f Z5 w! d; ?: l void open(const char* filename,int mode,int access);参数:7 y. n4 F/ y; D. X
" u8 H+ f, U4 W8 j! W filename: 要打开的文件名( W: C' @0 `, T. f$ Q8 K
8 G1 A/ d. ~! \, P0 o; Q/ I3 v2 j mode: 要打开文件的方式
+ ]# H, p& C4 F+ g* M+ F 0 {* Q3 z9 E: z# s. t
access: 打开文件的属性
. K7 I; W/ O+ \3 X " H& |9 J$ Z5 b7 T
打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:
6 e6 F( z5 S; N# Z, u; V* m# H; U- A - s: a: i0 \! g9 U6 u; S2 G5 D
ios::app: 以追加的方式打开文件
1 a' n7 N9 F2 Y# q7 H9 M: X9 A ( ]6 }. `/ ]" X6 g
ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性
# G% s7 K8 E8 D1 K
' `$ r& v/ W `: N ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文' [/ U- }; D! T* c* D. W
5 z5 G: y C" o! h, s
ios::in: 文件以输入方式打开(文件数据输入到内存)$ m A, c4 y2 c n& @2 W
# W) R1 w, o% n8 m5 Z ios::out: 文件以输出方式打开(内存数据输出到文件); k* P7 f( c- o( o c% S# T' s/ ^
& X$ s+ c3 A* m+ U ios::nocreate: 不建立文件,所以文件不存在时打开失败
3 L }' _$ D# l9 a5 X# s5 Z! r % F/ W' M. s3 [5 b- `$ }& \9 v9 K6 _
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败' y/ z6 C) b4 @" [1 [& W" P
" N0 K1 v8 L' `$ C9 t* x* [* S ios::trunc: 如果文件存在,把文件长度设为0
I/ j9 @) d# ]7 ~' S" k
4 m, P' M2 k8 O" `" @ 可以用“或”把以上属性连接起来,如ios::out|ios::binary$ o6 i$ q8 V* }) }+ G [
( W) i; C3 l. i- D2 N) \/ b& J
打开文件的属性取值是:
: Q3 I4 Q# S4 C
5 J! P5 |- U/ D! l: b6 C# ]* r 0:普通文件,打开访问! G* o& W7 t& p6 f: D$ [
$ F6 k( D4 V/ T# p1 ?$ H: L7 V 1:只读文件3 |8 D, s, Y# X6 q1 T4 V
7 O; {8 b+ @0 F+ |/ x
2:隐含文件$ L) ^' J5 L. z$ b6 i( F% a
- m; R: B7 z2 o9 V+ o, A; Y
4:系统文件
) G) k- q2 H2 k3 [: w0 L 4 A! \! W( S4 b$ }% f4 ?
可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。9 O% j6 k; h, t$ t1 r
& R, Q/ r9 _! P 例如:以二进制输入方式打开文件c:\config.sys4 w) t# D* ~; p! l7 j) b# K
9 M0 L' o3 J, f e9 B0 M
fstream file1;8 T/ R$ Q% `# r0 c8 o
6 ?0 B$ K2 ~7 e/ a; q file1.open("c:\\config.sys",ios::binary|ios::in,0);2 v+ V& {' ^5 u3 d+ G9 _
6 t# V. E; j0 h, l 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
' [) M( X0 s) J" o* U6 e& P/ k
: l, v, W5 \% l, E file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);0 X8 X2 L6 m, t5 |' k1 V; G* Q
/ V( ?; D; P! w" v6 o( w0 C5 p5 }- \
另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
. Q$ H0 v8 G2 D/ M& B : p% v( c" w5 F) o; s
fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
' d5 k, i# E1 a ]+ c7 E 1 Y0 N6 h% r) ]" L1 r, j- U
ifstream file2("c:\\pdos.def");//以输入方式打开文件) M; y! k$ V. e; V8 K
$ Z( x. l/ m7 Z' \- x& T
ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。% e0 l A& l- }. {
l! N2 b$ d6 c, s( k% S1 [
二、关闭文件( U1 t; T3 f$ H" S* E0 D7 G+ f
. A2 S- G( c. l' y. G4 D; N 打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。
. Q7 d4 s* A. |1 v G3 O
8 Z1 m5 X R, m) ? 三、读写文件
% ~& t' i1 I( ]2 f) ?5 u B
8 w' u. D* k, j$ S 读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
9 d! `7 J: p& \& y, g. V
: m7 X9 E+ T' w! u" x 1、文本文件的读写
+ s0 h/ [1 O0 q $ o+ g O$ W' g& d" A% K
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:
9 F! _) T/ C4 _3 @6 L ; q3 h/ `6 A5 m4 a
file2<<"I Love You";//向文件写入字符串"I Love You"# O! g1 y: V& M1 s' P
8 T2 F! j* U6 h/ H; c# b/ o7 [ int i;
! s @3 K- n( z) z$ `# D7 }6 I8 t
+ a# y3 o# o0 @; X file1>>i;//从文件输入一个整数值。
* m% E5 A7 H$ i& B3 W8 z* _ . a, U# W( c$ M' ~; H! B$ {
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些8 n) _6 n) _$ N6 s4 M5 r
" s/ ?+ s/ k, F, n; ` w
操纵符 功能 输入/输出6 u: @! F5 a+ @0 x% t3 ~/ ~' l+ C4 ^
4 k1 \2 _& V6 _! V. Q+ R# B
dec 格式化为十进制数值数据 输入和输出
( {4 f! ^& d9 v$ w3 L) P; l }& _ m: x& @5 t% r. f+ h
endl 输出一个换行符并刷新此流 输出
9 L. D) w( n. V4 y - \/ W0 V* @/ n
ends 输出一个空字符 输出+ P$ \, P8 g! r* ?# R
7 K8 R4 C7 B6 V2 { hex 格式化为十六进制数值数据 输入和输出. C7 Z3 k+ x) p& j; D. _7 r
1 H" Q! \7 C- P& k) G" p
oct 格式化为八进制数值数据 输入和输出
# l) w5 B, a5 N7 y0 j, L ; t7 p1 X7 J( C4 n, E( _/ C+ g1 O
setpxecision(int p) 设置浮点数的精度位数 输出$ h& o6 u* [* {3 b, L
1 P% @6 L6 a7 I; I+ m) e2 W
比如要把123当作十六进制输出:file1<
$ x7 m2 S2 }" a) n 2、二进制文件的读写7 x$ Z& ^; w5 a2 A) W1 O& r/ q
! e& p6 h( D6 ~7 {7 G ①put()7 |1 |# ~& l) }0 `6 W4 w( R+ v
- l% x4 B: ]' h# } i- W
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
: s0 D$ o# f9 Y
2 B+ F( v! S J. z! y/ H8 D) c, [9 S ②get()% Y$ v+ h8 P2 r; p, j
9 L1 O, U {& `& K# `! ]! c/ v
get()函数比较灵活,有3种常用的重载形式:
. ]& W+ p# b3 C h9 ]1 x % ]/ V q# `/ k4 u7 l ^
一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。+ h) l" D) H7 Q
6 L6 N H u, b7 w
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。! S& G, C( \0 l" k7 Q! f: C5 j
5 l" K8 f+ t" d/ f3 [. U. h* c
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:1 }' z' }9 _" E
$ T+ y4 _# e: G9 @4 k file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。# X5 j/ y# l6 y8 I
4 t; Q" v9 o) u. \' h4 V ③读写数据块: D: u8 Q4 L7 |- l
* P1 A' B7 J: S7 r 要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:/ C6 Q. ^( x# y# U+ }8 ?: t0 K
) i& J" B+ E# K/ W& @
read(unsigned char *buf,int num);5 Q, Y7 ]! i7 f. T8 l9 D
I1 S/ _. c1 B0 }( p write(const unsigned char *buf,int num);
2 G4 A' I* t% i! m
' h; W2 a. x' t0 E) x4 a2 i read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。( J" A K) n' Z) m" `
! @# R4 P2 s9 G/ @9 v
例:# M" q7 Z4 `3 b0 N* ~% U# N
" z. J- ^. w/ t) E0 C unsigned char str1[]="I Love You";- a6 x/ P5 i1 v, V
! S; L6 o& W- c) |1 c$ t
int n[5];
* ]: z% H9 T) m; |$ L1 p2 m% W
P$ e7 Q' ], t" e1 t) T! _% M ifstream in("xxx.xxx");3 M& {. h7 k# a2 A
! |- v7 k" u- U" h4 U C ofstream out("yyy.yyy");: }6 s$ U- g6 S8 g
2 _, I+ V6 r+ }# _# {
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
( H: t* _. _$ o* @ 6 [" e8 `! G h+ f2 H/ Q
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换; i$ `+ Y& K& C7 E9 q
" l; |) ?) q8 Y
in.close();out.close(); 四、检测EOF9 M& X) ^2 r4 y5 Y7 y9 a4 i/ z
6 V5 X0 C3 }/ ~' O# S
成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
6 Q' c4 t+ L' p& b7 q \ 9 {* M# k7 B S0 V% x
例: if(in.eof()) ShowMessage("已经到达文件尾!");
2 ~& d, ]( p' f7 v3 k
4 m3 B0 c) n) i1 E& H* s1 i 五、文件定位
/ N3 c8 W( O- v7 {2 v8 S1 S
* H: H2 O/ ^8 }" E+ J1 u( G( T 和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
1 d! g& w$ R$ ?% X+ X
# P9 R( B4 ]$ X istream &seekg(streamoff offset,seek_dir origin);
) G. e% [6 `2 c4 L9 x
' B+ _6 @0 [. T* d; G$ x; p2 Z ostream &seekp(streamoff offset,seek_dir origin);, F% Z$ {2 e \6 Q- z
6 X, U& \% d$ Y" k& J) R3 z, R
streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:- W. U" P0 i& ]. c$ g v4 P
0 p& e+ e3 f' a! B( d
ios::beg: 文件开头
# L2 B" G: t/ }/ G2 t7 _6 r: s. B- P 9 z9 B5 |( w) l8 d7 Z4 {( G% u' ~
ios::cur: 文件当前位置! C4 `# ]; k$ R5 T
, n P( o1 j! ^8 t7 i ios::end: 文件结尾
& L2 T8 W3 E" \. b2 ^
; r" F: @+ O+ R 这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:. F+ r5 Y2 ^5 T
) P* `! z& H$ Z) ~( j
file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节 t! ] K8 M2 j" y
5 {# W, H r$ f# P. J+ |% t3 d4 ~
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
& t. F3 C2 j3 Y4 Y8 w$ L1 `; P p1 [ D% i5 _& j7 ^& S
|
|