|
|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;: H! P( c# K: g8 A. \
, W9 H2 `& R `0 f$ X" [ 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:
" B# h+ F+ y* G 0 E( p G0 d- x
1、插入器(<<)
6 P6 x, ~8 x% K0 `3 `
8 s6 d( J' r$ ]; c' R) w 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。$ ?# c# ^+ ^8 K2 n! {
+ z& J2 h+ c0 J# q9 V. E, H
2、析取器(>>)+ g0 W, c9 q, s0 |1 v2 L4 B9 @
. T! R7 M7 S" K' j0 }' [/ M 从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。3 V( `) @4 }4 O( C% L& {
, w. f4 A, q% a: {3 L3 C- Q
在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。
& D7 j6 ~, n& n4 @8 b / e# K ^! Z: `2 ]
一、打开文件
) Z4 A- @5 H7 B& L- k
7 i c: p5 }5 a/ } 在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:- E& n# G8 R* \& d. v3 T& I1 y
) R1 D6 {3 I- H5 b% K: s void open(const char* filename,int mode,int access);参数:
4 _' F7 n% @% N8 c5 W$ I1 N# t8 `
1 O7 L3 Z4 y8 {- H' N filename: 要打开的文件名( R" X! u! _. k4 [2 \5 C- Y
. X/ a* ]* |& F$ b
mode: 要打开文件的方式' `0 @# Q2 ^* I" R7 C
7 `! f9 A& U7 ~( q0 [
access: 打开文件的属性' V8 e" m) W; }8 h! c( P
9 i. o) h- ^% B8 b
打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:
5 Z/ z, c% r0 N. @& d& J$ U" n
5 z9 o6 _' x5 j; Y0 W# { ios::app: 以追加的方式打开文件
4 w6 v: m1 I9 i6 }& i
8 T' E8 `. i# N& t/ a( t ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性- t3 N' z \# w, ~
: X3 m* R- o T) E: [: ?, D8 T
ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文: ~3 I" g( ~/ @- ]5 y
9 L; M8 D6 d( a1 T* y2 }$ w6 J/ ]
ios::in: 文件以输入方式打开(文件数据输入到内存). @" d7 I, G% ]: s* s; m
' e6 F; x: U/ z6 L ios::out: 文件以输出方式打开(内存数据输出到文件)
: |/ [& G8 e# A* b+ C / m" X3 X! I( ^
ios::nocreate: 不建立文件,所以文件不存在时打开失败$ e, g/ [: G+ u7 M
1 h$ S" Z9 ?/ K. U ~7 b
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
5 r3 w4 m( Z4 M% r" ^" P* ~% V! { * V3 K& k% _( a2 i0 q6 h# c/ d
ios::trunc: 如果文件存在,把文件长度设为0
% K3 e3 }# }5 m5 K' B: x% j
5 [3 ~: Y; E% N+ U 可以用“或”把以上属性连接起来,如ios::out|ios::binary
: ]5 x. M" e4 Z% x t
7 @1 F! S2 Y% {. |: Y8 K 打开文件的属性取值是:
; ^1 W4 ~# K& ] ; }; p3 X' d: r
0:普通文件,打开访问
( J3 T9 C" a0 a0 b F3 T9 Q6 M : d& i6 J- n2 }! K0 y
1:只读文件* B4 g* S) X( V. h C2 p1 @
6 U9 d) \' {4 {6 s 2:隐含文件
: g, T" Y; r: F8 q& e7 G$ s7 a
- s/ B6 H; W. F4 ` 4:系统文件0 ?3 P/ V6 Z2 t }7 K
) @: z+ K5 D& ~
可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。
2 Q. Z# U# Y2 ]6 [6 e P
( `7 J3 c: J: ?8 ~" H 例如:以二进制输入方式打开文件c:\config.sys1 p( K1 J+ n q0 p: l; h
, U' b5 L4 o7 t. b' W
fstream file1;
6 I1 U7 R2 Z/ C
. f+ p. n; I8 A9 A$ e0 U i( E file1.open("c:\\config.sys",ios::binary|ios::in,0);. n/ E5 L/ U" |5 z
2 s+ v1 M% b) I+ x* J2 W 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
1 } Z; E% G' r8 k/ o: Z
n5 T8 k; @* ]) o8 A7 m* V file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);, R8 i/ l# w) s8 W
! j/ D8 e: I+ D$ c9 _ 另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
2 ^ }! Y- h* ?) m$ ]" @6 k
/ X/ X/ ^) y% h fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。! O" b0 V% L% B5 ]0 y" k) w
" x9 A5 s7 W9 I. K
ifstream file2("c:\\pdos.def");//以输入方式打开文件
! I- D1 J7 O6 X2 N* E$ Z' D
1 n9 N1 F v9 R0 ` ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。& c' x0 s2 l7 t! D8 [, g t8 t2 L
) o: Q& f! G/ [: g: p 二、关闭文件
: E: ~! a, J4 P
$ d3 r, c: ~: A+ N6 Y. _, { 打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。
( x8 W I' d( o/ H; ]- B
R% @* Q- ` ]% [/ z- l6 d& f' z. z 三、读写文件- F. g7 L' c8 J: L F3 |6 b
; ?: O6 ~2 d @% J" R+ ?* Z
读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式% D0 `7 _9 Q& Z2 o9 q' A
- b/ Z8 d2 |: z6 m9 c! ? 1、文本文件的读写) g7 W% r: Y5 N& ~) I) l$ `
- ?1 z$ z3 v9 p- W
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:/ _% s. {2 B- \, D8 N- {/ |
1 u( ]% F$ F; |& C4 f4 D9 ?/ B
file2<<"I Love You";//向文件写入字符串"I Love You"
& ^1 O$ y& V( B: p; L( T
0 C( `) i5 p$ ?/ V int i;- A K% j1 t5 l! \7 \* w
8 l( K+ {; q7 a1 I% a# x! T
file1>>i;//从文件输入一个整数值。
, G3 J, e' p8 n5 g( y& V
/ E2 ]8 b7 {, C/ z4 j 这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
, s* _ e( P! V& z+ G+ a
% v- H, m& i6 f 操纵符 功能 输入/输出) o" ]* n/ @7 y z( h/ f/ ]" j- G
2 y1 M& v' F. A7 B
dec 格式化为十进制数值数据 输入和输出/ {9 ?4 P) s: O$ U* ^# r6 K+ r5 U$ f
& e' g* X/ I# o. b* X endl 输出一个换行符并刷新此流 输出
! K7 f# j6 O+ F2 y7 T 5 F2 e+ l4 h2 c( {5 P3 V& K
ends 输出一个空字符 输出8 e6 T, i- y7 ?) L' ?% N
2 D+ \! f% ~7 t) d/ \$ V( \
hex 格式化为十六进制数值数据 输入和输出/ d l. c L+ j# N
( R& f/ i" k o/ h+ a z1 H- J oct 格式化为八进制数值数据 输入和输出" y* C1 W- @0 T" y3 l
; F `9 a+ j7 ?- [7 `
setpxecision(int p) 设置浮点数的精度位数 输出& _1 X+ p+ f% }4 t: b4 `
( n) S0 F9 G. W! Q 比如要把123当作十六进制输出:file1<+ ]" C4 @" P9 Z3 f4 E
2、二进制文件的读写3 ~9 J: g/ J6 j _0 l: X
* R h/ O$ S* h" x. v, g
①put(). V i; p" Z+ n( K! C
% M% U. u' i. W. w8 d' n" B. m: X
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。* \* U3 y G- a- U! B
/ b" M& N( W2 n2 ]4 z; L& a/ V; p
②get()
4 K# \( @, X$ `+ I7 J 7 {5 Y2 F6 a; v) @" e
get()函数比较灵活,有3种常用的重载形式:
: L% m U6 \5 b5 L
8 K% U v9 z# M' @4 p# e. J/ x' O 一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。* r. M9 f9 F l+ j1 @0 M# D
t( Q4 Z- ~$ A, [; J
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。8 D5 Z# I# o' c$ @" Z
3 u$ H6 u, w" W/ z. W' \" k 还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:' q, j8 f" t6 x4 Z3 }+ e4 L
! y6 b0 A: H& f7 W% Y j file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。
" q- m6 }6 t& J& \, x; c5 r
% s. }, {6 y2 G ③读写数据块
; C3 ]) @" V+ j0 d0 m: E; o 1 ~% a3 t- Y& u$ \0 n E
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:
7 e/ d/ [) n& M" h8 X
* j' ^; b7 N" y$ V4 j5 v8 l read(unsigned char *buf,int num);
! ^; O4 ~5 q9 U- x2 u" V 5 N% x$ I# \( d6 L# I1 G3 a
write(const unsigned char *buf,int num);4 A# P, x3 [- ?. b0 c
l( H, n6 |- @: H read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。- v6 }2 o9 s& @ V2 \/ a9 |
. v. }; h. f% b! N7 n
例:6 h4 ?( F' ~! q3 ~; d
# k2 a! D+ A: |9 k) P# O) k
unsigned char str1[]="I Love You";
8 n4 D& j$ X, I) Z- x8 ~( M 2 V" z& c2 f" K/ [- O1 c+ v
int n[5];' x% c1 Q8 {- i6 {
; e2 {- _9 S9 s2 z4 ? ifstream in("xxx.xxx");% N2 h0 m$ E' T( P+ K: f
e. y; ~" \8 @: p% _6 D ofstream out("yyy.yyy");, ~. _! T! a& [0 k0 l3 K% F) Q0 U( v
; q1 N6 P" s. p0 z* F! Y; i P6 o out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中7 L# g) Y/ v: c$ m. L$ I( |$ h! w; F
; g7 U* B1 P7 p, s. ?% d
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换! X5 j; y# S$ H
8 j( f1 f& j1 z, |
in.close();out.close(); 四、检测EOF3 F" x! e5 n) T8 V1 _# z
+ y' j2 {# s3 V2 s ]8 k 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof(); }7 ]0 A9 R) w! i) I
6 A, f0 U: z: R$ v: z: Q 例: if(in.eof()) ShowMessage("已经到达文件尾!");8 n3 c' A0 P' c5 {- \
6 X3 e( q8 e% b- v; b9 a' a1 b" m 五、文件定位9 u0 r, J% F* z
' V- X5 P' a7 A* X; a+ B W' }- Z 和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
; a5 d4 o. L/ S/ G6 {0 h# ?. j7 I: x
5 M1 r3 A/ S. p" `* D# U0 d istream &seekg(streamoff offset,seek_dir origin);- l4 ~7 r: D1 ]/ j8 j( W5 p1 c
6 t' o" R" C7 I3 {& @, Z
ostream &seekp(streamoff offset,seek_dir origin);
; m4 r6 q; K7 l/ g8 ^
/ }' E8 I- w V: Z) k1 j `% K2 S streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
# ~' t5 D, w) Y; E ; \7 c/ C+ k0 t# ]& `5 I% c
ios::beg: 文件开头( Y$ a$ Z$ A5 x& J$ ~1 |" h$ ^
& l3 Y# Y6 d7 ]
ios::cur: 文件当前位置8 X. g/ b/ J. p* t
) D! o2 O2 [4 D# D9 n# ?! R7 C
ios::end: 文件结尾
0 k+ ]2 A# R' c. {& a5 ^ 9 @- X' B; v8 v& G
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例: f% F6 @5 E8 z0 P6 t
8 O$ I% R" C6 y1 a6 }" \ file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节
& M- Y! v: ~7 F' ^' b) {4 d4 h# u
, Y5 x1 Y1 q- t$ C- D2 I& E2 j# [! v file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节7 S L: a$ w8 G0 m- Q a/ O4 W
- d- `; h+ Q, P |
|