|
|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;
3 ]# y6 b: S" T: x! f , E+ _4 |8 D4 I6 S4 o
在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:4 @: A; q& n; ?4 X8 ~
4 ?& v/ `0 e) F' K+ U 1、插入器(<<)4 M( V! f! |; x0 N% d* Y8 @
, C F7 R4 I! M# S3 }8 J 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。
( q. w; h1 }! C4 `( _" F
; e2 ?$ ~3 o- D" d/ a4 h 2、析取器(>>)) \! M# u, ]( r
4 T+ r3 u1 `, g; P1 e/ |
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。2 n( W5 U, j* S% ]3 @; r% {' J
8 |+ |7 [7 E, A9 r% P. z
在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。% O/ i3 g2 C8 j9 l
" B9 t* V q7 ^3 i1 v" y 一、打开文件* {* V$ T& ]2 O2 M$ B
3 t3 m1 H% O% F& j, a; N/ H
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:
3 e: [9 N" S& I4 _0 p: g
% t- w. ^( o7 p' v8 H/ X void open(const char* filename,int mode,int access);参数:
+ [+ D! o6 N4 K
$ E/ `; V: [; q filename: 要打开的文件名' C8 k+ G i& d5 \% s
6 }0 D% Z0 z# N0 w" r
mode: 要打开文件的方式/ d7 ^2 Z' U4 `6 I% _$ t7 B
3 Y, F* }: L0 l" u! Q4 e access: 打开文件的属性3 m* _. P6 M5 {/ d* X. b
+ h& Z7 L+ _$ Z" G {
打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:+ o2 X: Y- F" t$ w; a
$ v; P' `. g5 G7 |7 M$ C" _ ios::app: 以追加的方式打开文件) O, \. I- F* w: {8 d. Q, q0 F
( Q9 `+ u) Z% h! s& U
ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性
$ p; {5 H9 }0 T; ~) L2 @
8 ~# S& y' D( X, {( r$ J ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文7 s# P5 _- }4 b% y1 {4 N, i1 K4 c
0 R g# J1 E7 ]- J9 d$ g ios::in: 文件以输入方式打开(文件数据输入到内存)
- Q! ~; N) Y, `, |; @ C% L( T0 \( L
6 n' b$ P2 S" k$ e7 j+ L ios::out: 文件以输出方式打开(内存数据输出到文件)
5 o6 K, `8 L! x0 o8 q4 G! r! h, f
V" n# G' C9 f8 D) E8 ? ios::nocreate: 不建立文件,所以文件不存在时打开失败
I8 k7 O8 q2 r6 @3 }
+ L* S# [+ ^7 v% ], }* |" L* y ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败, _* Z; h0 r8 b9 a2 x$ f
B6 h! ]# `6 i4 |4 S9 m: ~
ios::trunc: 如果文件存在,把文件长度设为0
" S( s1 L: j$ E/ b7 T. g/ i 8 u2 K; v5 W; I: W1 m
可以用“或”把以上属性连接起来,如ios::out|ios::binary
# Z( A6 p# N" _6 E/ d/ D 3 t( {* O1 G( V! Y* R
打开文件的属性取值是:# z& x6 X- T0 n9 a' G
! K; [7 t0 j7 E( p: M( E+ x5 E 0:普通文件,打开访问
, y8 [$ n u$ V ) y. f A2 v5 j! j7 c* \8 o
1:只读文件
0 J a/ E, B' r2 ?8 _
+ D _# j+ u, k3 L- y 2:隐含文件
# t" w! e, F, d v0 l) q$ M& h
# h# o. m4 ^1 a: O2 P! d 4:系统文件
7 r) l9 b' L: V+ l) L x
9 N. U$ [. o2 e+ F" Y 可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。' E0 z/ |1 _7 V. L u; V0 h
[7 N6 Q" ^+ |- t5 ]5 s2 f! q 例如:以二进制输入方式打开文件c:\config.sys; e" S! s1 u6 ?
' R6 y0 h0 F/ O% ]1 l4 v$ S6 d2 B. M
fstream file1;- C4 O3 E6 [, n5 ^
: }! p' I0 ~$ n1 @4 T+ {
file1.open("c:\\config.sys",ios::binary|ios::in,0);
8 W! }. W0 X B/ P% z/ h
: ?$ R7 o/ \5 P2 j. l 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
% g$ W# |) G+ I J" w1 b9 I + [( p0 [ l0 B
file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);
6 s. c4 k( f" n8 O4 _+ o , K, D4 @: G' S7 Q& o* h! L
另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:) E0 A# G7 ~, S# z+ T* b6 Y/ e
+ [; o4 n) S5 S fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。 \, |% r, y9 r
1 B; M; G2 P6 ~1 [% x% t6 d
ifstream file2("c:\\pdos.def");//以输入方式打开文件
0 m- t$ q& _% r0 y% R
4 u) u9 b# _: ^9 t& _9 ? ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
$ x1 Y* i: \5 w1 o- @ A & T1 X! m x: [7 P% Z) Q
二、关闭文件7 r4 ~6 D9 g6 ?' }5 K7 b
) `7 c+ D& }7 v! }6 _- ?* G
打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。8 @( c( K7 N; x0 e6 T( J" `
8 p4 D4 c( ?: k2 e0 L/ y2 _
三、读写文件# X+ u/ r) x1 P% H
5 m) }3 Y2 r% u- [ 读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式+ Y+ G% A- m# u0 n; d
; K% q- }- `! g: s/ Q1 S
1、文本文件的读写. f* ?$ x; q+ x2 b! k+ I
: q0 O5 A" g j- V2 ]3 o
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:0 G& W1 y: r8 R0 a0 ~* w6 {9 K; T
6 T; d* }% u) D" U9 I& }* c; t
file2<<"I Love You";//向文件写入字符串"I Love You"
' ~" I) r8 h* J
- k' L: ^; y4 Z int i;
5 P8 H: r n: K+ `% t : P0 w9 ~7 w& h1 p
file1>>i;//从文件输入一个整数值。5 R% q" V% M- Q! O
5 m; F) t( P* U
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
. [# i8 i" ]' o# s7 I - r5 s) v, o9 @" O+ H O/ u6 g- ~
操纵符 功能 输入/输出
' \0 \0 n' a! C. @. k
( _0 k& v, n# h& v/ m3 ] dec 格式化为十进制数值数据 输入和输出3 D) R) A2 B, k! A) r7 U
p" H4 M8 }; d8 z endl 输出一个换行符并刷新此流 输出
5 {0 i9 A- G- J" H, D
* m' H8 Q& E& B( M" U ends 输出一个空字符 输出8 ^' q3 o$ Z+ |! x
0 Z b- @* c5 j' y3 A8 S) Y8 C: p hex 格式化为十六进制数值数据 输入和输出
i4 k+ f" `' c 7 C# E4 O+ V" |) d. p) |
oct 格式化为八进制数值数据 输入和输出
+ ?& P! r9 y# ^1 M( e. Y% g A2 }/ d$ z! e' y# I8 a9 O
setpxecision(int p) 设置浮点数的精度位数 输出$ {' w% m5 F9 ^
6 ~0 r% S1 A' p2 s! O 比如要把123当作十六进制输出:file1<
3 b3 b( E* N) x- E 2、二进制文件的读写
% v2 N! E& ~7 G9 J% T0 K( `
5 [4 k5 K4 |# i: E5 i; j ①put()
1 n4 F, m& C. o" ?! U - ^- d: j. k$ z( g+ t7 Z- ~
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
3 o8 N) ?# w( v) t9 x2 T0 X
! n9 X7 X) J" O/ j ②get(), t" }' }# L5 _7 F0 f |$ t6 b
0 d. d) U, S9 ?- f/ z get()函数比较灵活,有3种常用的重载形式:
7 [! U J, V2 @4 E* Z1 z l & I$ Y& Z% T1 Z( r4 L3 u7 v* i
一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。3 z# U% p, `; b5 o
' G8 U: [- B2 K
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
: v; J& @; ?8 G4 G( b" ?
. R ~ I O! s' d, z! Z2 t$ d: b 还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:6 f+ H4 l5 Y4 v" l8 U
) @% l9 Z/ \+ k4 L
file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。" r5 O0 \' g2 x4 \8 F
) \+ U2 T/ S- E1 B2 e2 h6 f
③读写数据块
8 z& O$ H8 \9 P( \ 8 b% H. N0 g% [+ B- t% Q
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:% T Y$ F: F5 d% M( }
6 m$ X7 \2 X% ^% b6 ]
read(unsigned char *buf,int num);; v- G' T& l# M3 O. C
/ ~# k7 ?9 Z( [! R write(const unsigned char *buf,int num);
; l/ z# Z2 u' ?: j. @, f; R ! t( w& s3 Y/ A% k0 B
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。
4 K1 t; P3 @2 j9 S( q v: Z* T 6 ~6 H$ M, @* D* Z$ U$ ~, @ B
例:
1 m- `- q4 Y" x8 Y7 H7 S
+ T) T$ A9 v! Z o- z5 E unsigned char str1[]="I Love You";
, M' |, [0 z2 w: g$ K6 i3 v
. j( o! r* }4 i- m int n[5];* n8 t ~4 Z% z, L0 t
/ O& R6 }2 g3 O& e: K6 j z' Q8 E ifstream in("xxx.xxx");
6 P6 j9 F( f ?& B
! n7 e; W3 R$ z/ _" G ofstream out("yyy.yyy");
; {( I2 A0 e" c5 ^, ^
, F* A7 |# o B0 b out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
5 m6 O7 I# s+ I5 z ]. N
; x: ~' a5 k6 R: K$ G in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换2 i8 H* V" L1 R S8 y% E/ h
0 c2 B k1 i! i& V3 {4 {2 c
in.close();out.close(); 四、检测EOF3 B$ h [1 p: S3 p4 p
4 n# O" ]: v4 Z; F
成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
8 E- _: P4 N, q2 n/ C: I& x: _7 N
& n: m! m% l. Q& S3 R 例: if(in.eof()) ShowMessage("已经到达文件尾!");- P8 Q @8 E/ v; t6 p7 [: z
: w8 [! \3 @/ g4 X' k 五、文件定位
* E l& C) g9 h 0 }4 @: y' o5 U$ w' ]
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
8 i4 k" a H+ i5 O* {3 w
! v3 d' f+ v- F" B istream &seekg(streamoff offset,seek_dir origin);- J5 L, s6 s* R
5 V- d5 k6 `: P" B) m ostream &seekp(streamoff offset,seek_dir origin);& G# S) j) V, o: X$ F5 |
7 I9 S8 l7 [) Z: J streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
5 [# S- z/ h0 t- D3 O% @! R5 r: A @ 1 |. S$ ^. q. I+ n
ios::beg: 文件开头
- G( C6 U/ s" r3 A% ~
7 X8 R$ d& m. h5 h% { ios::cur: 文件当前位置0 `0 G. T# w$ [; Z- K, A, E+ [
6 c) o9 `+ [# k3 ^( s" L ios::end: 文件结尾
+ v9 V4 v I8 C0 E$ Q
3 E- i; G) i( w" A3 N 这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:
. v. `1 p9 T0 j, q0 Q7 Z1 W# F
e2 E9 }, S; [7 {4 l; C file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节
C0 [$ ?0 W8 n+ N/ J" x
; m9 O4 @- ?" m+ b! u9 b file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
0 o$ l y6 C) d! }' F
, L$ ?' Y/ K R, u: V8 o |
|