|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;* b+ N- z" [: s, U( d# ?& @% t8 o
. V; i# U" n' X
在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:" _$ m$ x4 |, `
; ?4 \+ c+ }1 S 1、插入器(<<)
/ ]7 [! L2 ~3 Y0 f+ W. x
! I2 r6 ~3 A) h5 g3 W/ e+ ^ 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。' |1 \+ h4 l( [
5 s/ R0 X; m' m$ l% G7 J G 2、析取器(>>)
0 G* l1 x* E9 s
) T! Z# h! j$ Y# C5 \2 M. q5 W 从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。
+ K! \( n5 z# }0 J" D0 R% P5 u / ]! V1 N7 _$ _3 V% W0 c7 H. E
在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。 g% m7 k: i% f1 n' m
! R" J& E9 k+ b" O
一、打开文件' g; o f8 n# d) ]
' B# [+ S" H; s0 z/ ]) o# t, c 在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:- g$ x, d* O3 \) H; T
. E# x6 [2 H% _9 Z
void open(const char* filename,int mode,int access);参数:0 g/ \2 e/ V) Q4 ~9 u
1 @: X6 U: m* E7 F/ R
filename: 要打开的文件名 r7 L/ }2 y3 U4 j* Z ]
& _7 d. D- u% k; F/ J
mode: 要打开文件的方式6 @9 j' R J% m# C$ R
8 L, x F+ H' D% X7 A4 n5 o
access: 打开文件的属性, z' l& o+ B8 e" c! @: Q( |
. |: {& t# F/ w# A$ K1 v% ?: ^7 Y 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:4 x3 U' f/ y2 ^6 _& B
: W% o0 D @2 Y9 f+ h( j8 X" H$ H
ios::app: 以追加的方式打开文件
; P. w1 D2 Y& a. B( M* N3 v 6 Z9 H; D: H( |8 P0 ~9 K
ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性
0 ^: d) j1 q- r, `, f
& R7 t% X! k( `2 I+ j7 s ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文: @9 d( q* V3 S6 X" D
; I; ]; J T- t! f( @3 `* p8 D7 j: I
ios::in: 文件以输入方式打开(文件数据输入到内存)
3 e- S: J% i I V1 T4 W
6 S9 }, T [3 b e% A' U, I ios::out: 文件以输出方式打开(内存数据输出到文件)5 e, \" q( S- K" p* ]$ Q
/ ?$ ~& P3 V, b4 H; z8 }1 W0 ? ios::nocreate: 不建立文件,所以文件不存在时打开失败
7 \- e! y' H' Q
$ P* o3 P1 w5 r: p& D ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
0 S3 d, C) e! s" S
! x6 h6 \0 [3 q/ c# a" L ios::trunc: 如果文件存在,把文件长度设为09 t" _4 R$ F% V% a; a; d* y# b
9 t9 l1 l+ r& W: H1 y
可以用“或”把以上属性连接起来,如ios::out|ios::binary
! ?1 \, |1 }" X' \# J
; k7 F3 E8 G: p 打开文件的属性取值是:$ Y6 ?4 [0 q. `' e+ o2 u
$ O: n7 Z0 n* C# p( l7 V
0:普通文件,打开访问
( A$ S- c# |4 N
7 ~ h3 N& {. ]% ~+ | 1:只读文件8 \% A8 e+ H! J2 P8 a" L8 F
8 { ^4 g* x2 N* S o9 A0 R 2:隐含文件
7 C7 d, Y0 L1 f$ R1 E( k) j
* W1 x7 c; t- S# a2 V6 T 4:系统文件
. H5 E! n6 I/ `7 _ % b/ U0 j4 E# x) \
可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。* O9 C8 H! o$ P2 X4 T; y( \. d
- b5 E: f4 r, E0 `; h7 z, e
例如:以二进制输入方式打开文件c:\config.sys
: W% p+ D! i0 I6 b5 C$ ~0 o
+ G; U, @2 q h- Q4 ]' v h9 e) I fstream file1;2 p% H C# `8 N# W; [1 q6 G
4 u$ e2 H) F+ O. p& N$ a2 z% y
file1.open("c:\\config.sys",ios::binary|ios::in,0);) P( O/ C$ M4 `
; i$ |8 |$ z( l9 v0 z: x 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:7 E' ~! _. _/ \, b1 [. J
/ b. S7 h9 g. f6 Q/ s" @: i: g file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);' S8 D7 U( r! {8 H
: ~7 w/ L5 U( u4 m3 K d 另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:( K M* l' H% \& `' B7 ~
7 i& d) H7 B V
fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。/ u% S+ a8 r. I; i/ R$ a* \
7 m; l$ {) }4 n' x- F7 c0 S, w ifstream file2("c:\\pdos.def");//以输入方式打开文件
( l7 M- Z1 r& k5 @6 v, O ]$ Y
5 a' C$ C9 R- \7 a ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
, H# q. @4 q3 D + l! u8 A& e. S i( h
二、关闭文件, n5 C! l1 Z% C V0 `$ q
. P( D% E8 b- h w 打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。" ?* C' h# ~0 P$ |) F3 j
L/ O3 M7 c! d; @4 l6 Q 三、读写文件
' D+ \1 P1 T' s* z. ~ 5 h& P3 V" o5 ^( ?) c
读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
; {: Y' l5 H& L3 R9 K
0 q# ~+ A, f2 _+ R1 a" d 1、文本文件的读写 G4 B4 T" K. \9 m4 G; @
4 M% `2 p3 b, [- O( r 文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:. s" C+ `3 {7 r/ c/ U( j
2 x" Y5 G- i, @7 G8 J file2<<"I Love You";//向文件写入字符串"I Love You"
/ [6 x5 M' \+ t `4 U, A3 M
0 N" y4 Y9 J5 |( ]* i/ Z int i;3 m9 ~( k* b# a/ b+ q# g1 G _ g2 x7 J
$ J+ E. }5 h$ Q0 U+ a file1>>i;//从文件输入一个整数值。
; x8 p$ s$ T4 T x/ [' X5 Y$ ?
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些0 t: H0 u( ?. v) F! { O+ h5 J
2 a1 w3 L8 l9 O9 p- M* Z0 ]. {' A 操纵符 功能 输入/输出$ B I9 _! J4 E3 i; j
: x% ~% n- v8 }! w5 N" t
dec 格式化为十进制数值数据 输入和输出
- w5 t; g. X) h) u, A% Y9 y , t2 Y& M& c" o, f6 Z& T/ N- n
endl 输出一个换行符并刷新此流 输出
+ @8 U6 [ |! U+ T P7 v1 @$ z% a o 0 k9 p0 M) ^ v0 i# V
ends 输出一个空字符 输出
. b1 v( ]% y7 X% V / h2 r3 { W; o7 }" K5 h3 I4 o3 h
hex 格式化为十六进制数值数据 输入和输出1 n8 Y% d( [5 m& G3 V4 t/ Y ~4 P2 {
+ I( N# F- M2 N: f
oct 格式化为八进制数值数据 输入和输出
+ a# o6 ]: k: u3 W" l- S, n2 g5 v% N
4 u' k! F5 Z V8 o3 t setpxecision(int p) 设置浮点数的精度位数 输出
# ~& d, q% e: e. r: i$ x0 q3 B8 g6 Q " j0 d3 O( x: c% `
比如要把123当作十六进制输出:file1<
! Q9 |/ n, V5 t2 u 2、二进制文件的读写9 f9 X: I! W5 o; w7 i5 y0 |0 `
* r j- Z9 Z) a2 @
①put()! t% W9 t9 \8 f; f9 ?
" R6 T& c5 u: {& Y' n6 _
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。0 e+ D4 j9 p) x* Q7 Q
3 o% [/ D' H# F- s ②get()
9 n/ N/ B c7 Q4 n # I4 J% [# M0 }
get()函数比较灵活,有3种常用的重载形式:$ T1 N" R" G6 W& z6 [! o4 c2 R
& z" C) j, }% j- s9 O) u 一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
: q) o* r1 U$ S, t" b* u6 L : c' H& d+ C$ H! \5 O) B
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。/ `# ^2 }" R* c% X" K; |
; \) v: B9 s+ t* [1 G# H$ X0 ?
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:
; {1 o( l# {/ u# K2 c: P4 m4 W 8 x' a( o' |7 h' f1 q4 Z, m
file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。
7 t" z5 ` x/ {$ g5 ~ . R2 m0 d6 _9 |3 [" J* s* Q
③读写数据块
8 \ Z) b% @+ _! w) X+ O; P 1 \ M' }, r- K/ r* ^9 b+ ~; s5 a1 N
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:; Y) Q4 t0 ]+ K5 R4 k8 [8 P
# u* j3 j2 O" V
read(unsigned char *buf,int num);
4 m+ a7 b2 _. C3 s+ D * ]) W/ S u" ]) e
write(const unsigned char *buf,int num);
' B! J# h' E5 \" C+ @; O
& w L: Q K) @9 f5 g; ~* P read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。
" D& _1 V: \. G; Y5 m B/ R
4 s- z# [: t% |! b 例:$ R6 a- z6 y2 D4 Q
: H% N. e% \& e2 D5 T7 e6 n
unsigned char str1[]="I Love You";
) l9 \7 U# s# a- c . x+ l! I @ ?8 _( z2 x6 h
int n[5];: c& ~0 c- v& w* P9 F* m
1 f2 Y! k. n E- |: Z' f# f* X
ifstream in("xxx.xxx");' k6 w2 C% e6 H& i% |
# E4 l% {- u7 z
ofstream out("yyy.yyy");- ~* x& c) K+ M
& T& F2 `* ]' F& `+ _% Y+ g
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中/ b( ?3 X% C5 O7 G& F
, y* q3 X$ [! n/ y3 _$ P
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换& g6 G* @$ @! P ^ v: {2 m
) n, B5 }# I+ {5 |: b4 r$ Q
in.close();out.close(); 四、检测EOF d! `+ ?; n1 H2 N" W/ {
2 q& c, f- T3 q5 a% @; ? 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();4 C# ~- g4 l# h1 a
3 ]+ Y" y$ g- f, R- D* L- o+ q 例: if(in.eof()) ShowMessage("已经到达文件尾!");
$ d2 z0 q. f# K
. X5 E& U6 D* t8 u" @ 五、文件定位2 T4 g! O) M, E8 d
8 A+ f+ f- ?# ?2 r2 ^4 Z/ x
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
! O0 r/ M) k* Q+ ]6 y# x- h# d " v) ?& A$ m7 w- }" o# @2 I0 b% `
istream &seekg(streamoff offset,seek_dir origin);) R' b) k2 M2 i1 {! R9 D
( G: r2 h% Q4 i ostream &seekp(streamoff offset,seek_dir origin);
% d* U4 E3 y y9 P I0 w A4 Q, B* l6 _' A
streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:$ n' h/ ~+ O1 B6 c! I
5 {$ h. U' r& q' u8 l5 a* Z3 F0 G
ios::beg: 文件开头& ~7 {7 `4 e( Q2 d& ]
& p% N( ?7 c7 K; G1 O ios::cur: 文件当前位置9 q+ U* `. ^* J6 I
" ?2 h3 ^, g3 |" U
ios::end: 文件结尾+ w! h G0 F O+ A6 t
0 D4 U$ M6 f X' G9 a" B) `
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:
p- ]8 j# M s. G" l* H ; j/ S; L- g1 x2 ~. y! s" p
file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节
0 ^9 n% t4 B, [ 2 \$ n( ~" K X6 B# n4 M
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
( f$ G _# R# W; J5 R6 o
- }+ {0 |3 E: ? P/ K |
|