|
|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;
7 Q# R+ d8 D, ~/ Q- X 2 Y9 \5 L, V" B9 s/ m, P
在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:
: N4 S$ V3 ]/ t2 {$ L ; a4 l+ ` ?- u3 f" I( _3 m- w5 _
1、插入器(<<)8 h( o$ o) B& b% @2 f/ A% h
8 f# i8 o- S8 [1 c" Y( V. ? 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。' I$ d% o& Q" I$ Z" i
( w; m( `$ m2 M z, P0 g* S3 j
2、析取器(>>)
; h' v: q- _3 X% B
5 ` o( O2 F/ C 从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。
% h6 w" Z% o% t7 D1 l. _. f
5 z( H7 v9 s" w/ l 在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。0 o+ Q4 p) A; r" l& E0 b, w( j
7 `" h1 o' k9 v9 u1 Z7 u 一、打开文件' P- H6 f e* O4 W2 j) w. V
0 H1 j* @: _. e. r, e
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:
/ Z [2 f4 _* g/ R' A
p W5 Q' q8 I* {5 f% s void open(const char* filename,int mode,int access);参数:
: d7 B% M1 @0 Z2 W V6 p; n
* e% z5 ?1 F0 A4 Z- ~ filename: 要打开的文件名
4 h8 H. V* u2 U& P 2 Q: }4 F1 O8 Q9 j: e: A# c
mode: 要打开文件的方式# `0 d( v$ @+ L/ {% m) T
8 \; R) W) D. D- o
access: 打开文件的属性
& h5 J- Q3 ?0 i
% _4 T$ [/ u6 o! ` 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:
; n, R! M5 F5 r" T; p$ P 3 @" y8 A& K7 u5 e% Q
ios::app: 以追加的方式打开文件4 w7 Z! E3 O% W1 f
2 y* \2 {: |9 g0 x+ w/ A; C% F ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性0 c0 p% C: o6 z1 I% u( c
* C6 T1 u, R) ?! [ ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文, U. Y0 R5 k; u1 |( K9 z) \
" W' y) p; ]- l6 n7 T, t
ios::in: 文件以输入方式打开(文件数据输入到内存)
3 v& f( N7 J1 q) b; m8 D
1 s7 k. Z( s$ ]' i! z/ d: [! H- n ios::out: 文件以输出方式打开(内存数据输出到文件)
1 B3 s0 c5 d# h; z5 l' w7 `
( u. E4 F7 K, L: J* Z" ^ ios::nocreate: 不建立文件,所以文件不存在时打开失败
D/ e I# h- N" y' T6 M/ v3 g2 L
3 o ~* \. g" }7 A( Z- @ ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
) @0 M7 Y5 m, |* v. U
+ C4 w, `: ^% K8 r% U. | ios::trunc: 如果文件存在,把文件长度设为0( o o5 R% n0 h1 Q
d# u2 u& y5 Z/ W1 u( b& }7 t' U+ G
可以用“或”把以上属性连接起来,如ios::out|ios::binary
. d1 f \3 Y8 D; E
7 ~9 D6 w' ~1 L" q9 M9 W 打开文件的属性取值是:
3 {" \( Y) D, m9 ?& g) j 8 {- C1 E, E0 M, h
0:普通文件,打开访问
4 R- V# B- ?% ~) C0 G+ e / e" J6 ]7 ^2 M. f
1:只读文件' T3 [7 K$ ^8 S0 m( I9 {* M
3 f1 H' J: D* a# R/ f) d5 q4 x 2:隐含文件# e; p& M1 V$ t/ m- l: e K. R8 R
/ g1 {1 }! C2 F+ v7 n8 @! i 4:系统文件
% C s! T% I) F5 a( Q+ ~( j. H: A ) @$ n2 k1 X. X$ g0 z3 U# S- S& h
可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。
9 D3 o8 Z, K! z7 d( d# z. G
8 o9 F3 Y2 C1 c( a( Y 例如:以二进制输入方式打开文件c:\config.sys
. @+ u1 o8 u+ M4 r# Y9 H3 A 4 L( Q7 N( T ^0 r& P& _' [/ ~
fstream file1;) F3 }6 V( i, z* z4 F
; q+ }/ Z& P( e5 }5 k
file1.open("c:\\config.sys",ios::binary|ios::in,0);* E; v4 S9 ]) y
9 Z; n' ^' @* j5 N+ @ 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
* i4 ^* P0 g8 l
- i: G7 \: v6 V. q file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);7 o6 J W- j' W% m
9 ^$ {$ B3 Q8 H" Y+ u6 x0 n 另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
0 F. e% z' B% i1 L2 u$ @ : ~; [( m3 f6 J# n( m
fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
! g# T# C# m- w8 k
8 @% {+ i: s& Y& y9 t5 v6 N @ ifstream file2("c:\\pdos.def");//以输入方式打开文件0 d# z0 f& |- s5 ? g% J
* }4 [5 I2 t% a1 u i& U" M
ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
8 t9 u8 i2 ]" \' B% |# k " R- F# K1 I, S8 i
二、关闭文件
! b$ c- ^4 O7 v: ~; M7 y
! |! V; a9 Y) t8 ?9 n3 U 打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。5 y' X- y+ G( G$ i5 R
3 C6 D: v) {7 y& J 三、读写文件
1 ^" w6 N$ B% P" c$ M
: J6 L, v6 ?8 _( n7 g" o 读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式% P( P/ @+ @, m
$ }: V; P# l8 I0 h 1、文本文件的读写8 \: D5 Z. w. L: `8 D/ e% |, R; X
9 a+ D; X- E; o0 I6 Z) P
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:
+ Y9 U6 X1 t: Z' U& ?7 k* b" @1 I
$ S$ R' e4 ~3 a; F' F! F. V# V file2<<"I Love You";//向文件写入字符串"I Love You"
$ @' m4 Y8 P1 ]9 Z# Y$ Y# t3 h $ e1 R' [& o9 S/ d& T' a5 _3 y
int i;
- T) B% }3 S) A- F8 Y, f
0 D2 G% G ~# M9 F0 V# W file1>>i;//从文件输入一个整数值。& W/ Z/ B' n) {
* ?, @1 }* N2 Y/ U. a 这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
( I3 z# O, u( ]1 ~# ]
1 Z i: Q4 q5 v9 v 操纵符 功能 输入/输出
/ e+ }7 Q# E3 Y: c2 v# g
# p, x" {& a9 L% M+ k dec 格式化为十进制数值数据 输入和输出
* I' K- N; f9 c7 P. M & N0 Z& R) t, L' P Q/ P
endl 输出一个换行符并刷新此流 输出 i% V# c* L. i* E5 k
. J# u9 Y6 g6 [! c, a9 h( @+ ?
ends 输出一个空字符 输出
# `" ?& i1 g6 `! | b1 f. \1 `4 H4 a0 o" W: c
hex 格式化为十六进制数值数据 输入和输出) j8 s: n6 f! }9 V8 g a) H% \3 f
4 p6 q/ U: p7 } oct 格式化为八进制数值数据 输入和输出
, R7 C% C% s& S- I0 J0 L
' T& x. m( Y4 W( K: \- p3 n setpxecision(int p) 设置浮点数的精度位数 输出
& k9 d( d% @2 {6 I* Y! V
9 U$ a" k+ C7 X7 D6 [ 比如要把123当作十六进制输出:file1<1 D% a# r" P, u0 V v+ A/ Y6 D
2、二进制文件的读写
" D: \3 a6 N7 h% r 3 @# r- H3 [2 l: c9 d4 L; C( U6 x7 V$ e
①put()
, h% h$ x+ W% C y/ g
: |9 M( b; C7 T4 V5 R4 C" D put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
6 I1 V o% |7 A1 i A3 D; x1 t
; r1 L; \3 H, o2 m, J+ T7 P3 k, h ②get()* z9 l8 {: {; Z/ L; G
( w) d1 C# v% ^7 k( y0 t' b get()函数比较灵活,有3种常用的重载形式:+ B8 r- [9 B% H9 w, I+ W; _6 q
4 b- H ~# n/ `+ m5 ~) ]# V 一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
0 i( X b" n( p1 g$ v7 Y5 r& p* o
: |/ T- D7 j9 [( x$ I 另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
5 |9 N+ \5 a+ _6 z9 X5 P
* N5 f- s4 p. u 还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:0 w+ v$ m$ v* m. K
+ t0 t7 v8 q; f
file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。; ~8 Q+ f. Z) t% Y+ ^
7 o2 ?( k: H/ d) a6 J
③读写数据块
4 B: R( y4 o: W3 `6 s! o% o
5 g2 q# m8 f3 s2 h3 t 要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:
7 h W2 j- W: p. w
+ ^% m1 ^+ J" u" M! { D- j read(unsigned char *buf,int num);
$ N+ C1 c& D( C( C: S7 J' [ : L( Y. R# z7 g" J
write(const unsigned char *buf,int num);
$ J( N4 |% M; R+ j9 c9 D z# g
+ U V9 A( w, H, W read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。+ ~$ W, g- o+ I' x' Q
" T# }8 _+ d: b
例:
3 z) o" G& x$ Y, S6 O5 W
: ^# ~: U' s, @7 _7 I( P unsigned char str1[]="I Love You";
5 r' y8 }/ D3 Z/ b9 R: a
& O9 s6 d/ H: A& C- P, u k7 l- i int n[5];
3 j, E. k1 g4 t$ }! z' e; l6 ^; r 3 H2 n5 a) ]( k8 V9 S3 E7 `; |
ifstream in("xxx.xxx");
- w' J$ w3 \. ?" E
+ |+ h1 z+ ^9 w2 h6 o ofstream out("yyy.yyy");& R+ F4 G% N, ]$ _. @
; s# r) \2 A4 b* Z! D out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
# y! d, g4 H/ h- N, n ! X9 v# Y4 e5 \2 m7 p
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
& C7 Q# b0 L, a8 q9 c: n; f
0 f: \0 P) V8 G6 e in.close();out.close(); 四、检测EOF
6 v5 p* v0 q$ Y r0 j0 F
/ V2 t/ B: X. j 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();( W3 v# b! l7 R' _) z
3 H, b0 Q @$ G4 A H
例: if(in.eof()) ShowMessage("已经到达文件尾!");# t' C2 c3 X+ g& v3 b4 t5 }
9 D5 P1 w; y' N% O 五、文件定位
/ u1 ^1 e$ M) e& z0 K! @% H . F3 J9 j- G! O2 I2 y; c& y9 |. `
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
3 f) Z" D; B0 U, x5 F ^3 q/ C7 f/ h& `
istream &seekg(streamoff offset,seek_dir origin);8 J( P/ s# c r9 k. |
: ?" f% v) Q+ \/ X1 t
ostream &seekp(streamoff offset,seek_dir origin);
O y9 j6 z& g1 K+ c* y ( a9 E4 l& ?, h, U- _3 m
streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
+ z8 B6 g8 }8 T( Y; | 1 I! Y. S) [: ^( P+ w i
ios::beg: 文件开头: H/ w6 x0 g" r3 {, q0 @; f7 w
1 I7 S0 @" G7 ^/ z& F. ?! b
ios::cur: 文件当前位置/ @# ^( Z7 E0 i* s$ n/ T
5 h% t n e6 F) o ios::end: 文件结尾+ X# {' _* X' ?0 [8 X, ?1 o6 D
0 f8 t3 w7 m- K+ L 这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:1 k) n4 [5 r. Y- }4 H
7 H% n$ }) @: w9 V file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节/ R7 a' J M& D2 j
. b6 Z" h; I- V1 U5 |, o# g
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
; d3 f2 B7 r$ r1 [# v8 d7 N
" G" A- J6 g5 _# A& A- c! P8 m0 {$ M |
|