|
|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;4 m7 |$ G1 v6 a) ]- ?7 A0 l
) A; s/ `7 l6 L( [5 T
在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:2 I: b" L: M$ [% K2 H- R0 E
, [5 m% x( r2 O4 U, X: p! d
1、插入器(<<)
8 |1 \: @8 R5 `
; U' G. u+ G8 U1 m. n- o6 D8 p 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。
7 P* {% W3 J% ?) ~: O. ]
! f( w5 L: b+ o6 d7 y' q) ~3 X; b 2、析取器(>>)
6 n8 ^+ f' ]( N8 N( ?7 Q
, g1 N5 M; i* `( _6 ~2 c: t+ ` 从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。; U' R! g4 ~+ y. V# N
% h- H. _- i* n 在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。+ M" A# p4 j3 S5 }
4 K: }2 m* @" N- [( s- m8 _3 X/ z
一、打开文件
c8 v. \) \* Q! ?/ a) g+ j& Z
5 g w' {) ~- t 在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:& e9 A5 t, ?. Q+ k( O; Q% K4 F
% G+ w+ V' L$ X' I; v& p
void open(const char* filename,int mode,int access);参数:1 m% c4 M8 s4 s* f4 L
4 j% G% [5 e8 K" P
filename: 要打开的文件名& k" Y$ C4 j4 L, K; \
% w! M9 j) @; J' v8 e! r4 }& h7 Y mode: 要打开文件的方式; i, N" t5 @/ q0 z/ e
4 }/ ~! `) h% G( q9 \/ ^( a access: 打开文件的属性' d E3 y+ P4 \! F$ N0 G
( ~5 V) t* a6 L* `# |8 U6 @9 L6 r 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:
+ d* i" ?, m% f5 O; o; w
* o: ]3 x7 @* W ios::app: 以追加的方式打开文件& s T8 N6 A. r* {
' t1 Q* d0 |, f+ G( h2 F ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性7 A* B8 d% X u3 Y. S( E8 W
: q1 c% U- M7 ?
ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文3 B* u- h& R* ]
r) f& d/ D* s3 n0 O9 l! }8 D0 h" k
ios::in: 文件以输入方式打开(文件数据输入到内存)
8 c n7 n$ H) Q# ~% b- l
2 J9 J' L( Q% o: w+ M ios::out: 文件以输出方式打开(内存数据输出到文件)
0 r* j8 y3 L- B. G! b, \# @ 0 ]1 C' @2 F$ Q- l
ios::nocreate: 不建立文件,所以文件不存在时打开失败
P9 ]$ M% L8 Y9 d+ t 5 Z" |8 W& _7 y/ g% O, ~, m# f- I
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败& J: `( K7 ?9 ~ b4 P4 F9 _
2 o6 L% T' q, L% ?& c# { ios::trunc: 如果文件存在,把文件长度设为0; Z6 _7 d7 j( N2 Y' i$ |
: X5 d$ n2 _9 K! j" r/ E5 P0 V 可以用“或”把以上属性连接起来,如ios::out|ios::binary8 Y0 a* i. K+ M2 h; A
R$ M2 y! p' ]; `
打开文件的属性取值是:
2 c( f! D6 `# g$ T + X$ ?8 N5 F. Y7 _) g- u
0:普通文件,打开访问
0 C" `; v3 l& a4 [0 e
9 \3 X, l/ u- O 1:只读文件
( H6 b/ v) s* b4 J! n1 u
. U! m$ m; Z% o. l2 W E! S T 2:隐含文件( K& ` j! K3 U7 F% a8 _; i
9 J' x- n( e8 ^% ?- ?! @& G% R
4:系统文件
" [) R G# w& r$ \ 5 r. f, q; C6 k. K7 _8 w$ r3 w
可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。
% @' k) T% \$ A6 I8 v
6 M; M0 I; v5 d 例如:以二进制输入方式打开文件c:\config.sys
& n2 W5 a4 X: L! Q
" h: |$ g5 ?) [2 T* V5 h: w. Z+ e fstream file1; c6 c3 a8 P% {4 L, r# J
- a$ h; u \7 @' I1 [# Y# ~
file1.open("c:\\config.sys",ios::binary|ios::in,0);' ?# s5 Q: h( ^" g; h8 ?% j, o
( A; R* z8 I9 }. u 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即: X3 Z8 \+ h4 p$ J2 I; [7 x
# I2 G* \! @9 ~; B. Y file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);/ ^& w) b: {* I3 `: {5 m) V7 c: U9 P
7 ]: }5 |+ n5 o) a/ A
另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:: @0 n. p, E# I5 O/ Q* R b5 I
- T2 @7 M" a4 D) g' h
fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。$ F# \$ f0 x) N1 l- P
/ D# {* ` D% c
ifstream file2("c:\\pdos.def");//以输入方式打开文件
& z% d" c6 s# ], D# |2 j! b ' \8 p W9 N$ e& I
ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。 B( l6 p- H) c0 T
! W& ~% ]" f# ]! ]6 e* B- R4 Q
二、关闭文件
. x" l8 r% h& H6 i0 C
, F( ^6 J8 T% q3 f1 K 打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。, y0 n- A2 h2 H# b2 m9 P
2 A9 c' U; P2 _8 |! s- G4 Q 三、读写文件5 E2 R$ G2 R: K% z
; V- q5 |8 V9 w
读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
I7 `/ P7 ~+ z0 x! h/ X & ], S( U0 z. |$ ]: G9 q
1、文本文件的读写+ @3 [) q& P1 n+ S) |
7 d9 S/ t* I( d1 U8 G) a
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:
# j% K' g! c- W$ g. E& n " y$ {* N1 h X7 ?8 u
file2<<"I Love You";//向文件写入字符串"I Love You"2 K b. A! V. y7 N, H8 P
/ r" w) d* }* D5 x' u0 c9 g
int i;+ \- `! x* c4 r( {2 u( v: N2 b
. o7 ? x+ I# p/ b, B6 p
file1>>i;//从文件输入一个整数值。
3 h" H N5 X0 J 8 d+ d ~8 V, j8 A1 Z
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
: k2 _# a4 \& R" R& {( g
. m' q1 _+ i2 u/ a; O# G/ k+ g) B 操纵符 功能 输入/输出1 T6 J8 q( ?/ Q. q) s, H
# V1 S5 v' I& a2 H6 ]1 u dec 格式化为十进制数值数据 输入和输出$ F- \( E8 @8 h5 M, ~
5 Q. _. x1 M! j5 a6 S0 z endl 输出一个换行符并刷新此流 输出: F2 a1 V7 K7 ?, o# ]4 w
( i2 e: X5 K5 x; W" H
ends 输出一个空字符 输出% {; h% ~. ^" Z4 ]2 X( w
7 b% @1 o! v) a. L hex 格式化为十六进制数值数据 输入和输出
! |2 c6 g# t) L, j) X. |4 n$ c# } 2 n+ z& P7 M5 S
oct 格式化为八进制数值数据 输入和输出
& `1 C- N2 q' i) K
4 ~- b/ e* G; v/ e% i% @7 h; M: W% u setpxecision(int p) 设置浮点数的精度位数 输出) x* f( b0 j7 f: R) g/ n
0 Y3 H6 \) O) F9 V8 r. u 比如要把123当作十六进制输出:file1<
- f I# R( `# M% E; G! d" `0 b3 e 2、二进制文件的读写% p" B& R. W u" |4 X
3 {& e7 ]+ V o* R- i+ s. U2 v$ g ①put()
4 \$ Z5 Z- A1 e
- d4 K7 q! _9 b- r. g0 P put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
# o' u, ~8 `( \7 x
% c3 n b- U; }3 k, | ②get()) f8 m$ _# T9 d( Z3 f
/ a: d0 @/ s3 |* e4 w2 r" a get()函数比较灵活,有3种常用的重载形式:5 V% Z$ e. @) o
$ Y8 T F- w( l4 @8 N) l( M$ a 一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。# \; ~. T( Z4 E2 K9 r& w$ j
; M0 \5 Z# w- a 另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
8 S; [8 U+ M9 i A; e L# |. |( \
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:
0 z% p# T) I4 e( r; V * m# i& b; O9 A, K2 `% F
file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。
1 Y+ b# ]" h% K, R
" w/ B2 l a$ b1 O- w* W) N( A ③读写数据块
2 z3 u# p2 ]7 L3 g( h / H, Q+ k0 U2 n$ l& z
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:
; q! ]/ `2 @9 f; O5 V
" j) z% d- d" U# b) I$ }5 F read(unsigned char *buf,int num);
/ c" R3 w4 i' j# g- P3 L
7 u" M( k, o9 R" \% I& v# R( S write(const unsigned char *buf,int num);7 `- O/ |! q/ y3 B0 F/ |& z5 W
8 {' q6 I- Y S. g W- U2 c8 p
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。! B6 ^( x) H5 {, ?* q @+ q6 J. R
: v: i% p: R2 U3 {% B" N2 F 例:
6 y/ f) J! ]2 h& b7 @ , [% ]. U/ i# H% e
unsigned char str1[]="I Love You";0 L( x: ]- B6 K! @! z
?* [7 J; U% l, _1 E0 e+ ~
int n[5];- V5 I2 ]( Z! T
' w9 h2 I( H; K5 G3 q& m ifstream in("xxx.xxx");
: x9 T3 S2 [" o; G' b9 J / G. M9 `# A( i3 O W
ofstream out("yyy.yyy");
5 r c8 @! Y% W: R
0 a4 a2 G' D' V1 V7 b out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中1 }) ?- r( R; @1 T0 Y8 U2 V: v
& I$ x7 ^! H: c6 t% z
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换5 G) z* }3 `9 A, [2 t+ Y, l2 {7 |
. X- D( L5 d( a4 c% S( M6 K in.close();out.close(); 四、检测EOF' n# h1 o% u& H O1 f2 F. c. q
/ \" }/ t9 m! s/ A* W 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
* E+ n2 X& a% D1 \! C- i
3 ~6 a: Z% M; U7 D1 D 例: if(in.eof()) ShowMessage("已经到达文件尾!");5 z/ T% S$ p$ l0 ^! d
/ U Z6 C3 L2 r" l# L0 V 五、文件定位
1 \4 A9 D+ t. Q( A) O2 \( p ( Q0 p) }) L6 M9 e% N$ J0 K0 v
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:4 l2 y6 e+ g, ?0 |. x! ?
: p1 U. e8 `; J: e
istream &seekg(streamoff offset,seek_dir origin);( B8 `5 H% ]" ~, H- Q0 N
9 }& i6 i8 A" t" d
ostream &seekp(streamoff offset,seek_dir origin);
4 H/ }- ^( F Q `1 z" b8 O' n' J/ U. O
: w+ `5 ?+ }0 U* _4 o streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
8 Q/ [% v2 \* P% L# o
- q. H Q' p! r1 Z( f ios::beg: 文件开头) e7 k- D1 v& J& Q% K1 e/ q& ~
& m& T Q4 v2 B, E3 }
ios::cur: 文件当前位置
9 V/ R7 k% `* R' {# G& a4 X
: d' W% y7 s3 o" M ios::end: 文件结尾+ C# T9 x; q6 ` m
4 L5 R' g) e- ^$ x8 ^
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:
+ S. N/ h+ T4 q1 R7 f* g. Y # ~/ k" F% g8 y5 \
file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节
0 t/ N/ P7 Z) V$ D. ?+ n3 {) }2 j! @ " `, P; Q- d2 u, P$ y
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
% M p: |( J: T7 T! m8 y: P4 r- |+ ?. H$ ~& s5 r. F! {1 T7 C, T7 r# [
|
|