|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;# |# L" b$ c- n0 `4 k
* t& a' q# A& Z 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:1 q2 O& N- d8 [
/ T, Z8 A2 R$ u4 c 1、插入器(<<)6 a/ g& D( y2 [) ]
8 L8 x% }( T- G1 w( h! U
向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。( |! V8 r F( @( I* q' T" i# j. a
) j6 Y, f: j+ I6 Z 2、析取器(>>)
8 c" x% g# R( c0 W% N# n
; ]" ]* Y- m" L+ C0 U 从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。
4 v @( \1 F7 x5 d3 l* h ( F- H4 p/ l7 ]( w H# E6 q& I- ~
在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。' x6 z9 T1 l1 w4 q+ {6 j1 s- l# j
( {& H Y2 f8 H5 a+ S3 c 一、打开文件" }2 P/ b" v2 F, u7 G
# F) n+ U& t: ~) h& s) t
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:
' P/ o/ b: e. C& v$ i: \$ B* o2 p + r4 `4 S! f1 D: `+ Z: J4 [2 c! Z
void open(const char* filename,int mode,int access);参数:1 W: I+ V, a; Q9 _* k
# D8 K! T F8 G: Z
filename: 要打开的文件名
3 W2 \: M; H0 c; `: ^" {/ r- z
3 L! x& n, i, H/ ^. T mode: 要打开文件的方式$ [$ g- C# Y; W/ x" ], [$ q
0 C4 K/ g6 C$ F* Y
access: 打开文件的属性
# W; ]3 y& l* o$ K. y
! T% u& W/ h; L. S e" B 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:$ I! `# s5 I, a5 l
& P, r, _( U$ P& g& }. c3 O( i* X( n
ios::app: 以追加的方式打开文件
2 r3 J; m( X. J7 u% p
4 S9 h( @' {8 X" C ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性
* u( t( W1 r+ }0 h% q2 W
6 G3 s, M% R$ f ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文/ S( O' q( C, m: x9 r
7 r4 L- j1 e6 ?8 U0 M ios::in: 文件以输入方式打开(文件数据输入到内存)% L% Z9 s2 z, Z! q3 } y, n
, v5 [ N' {; { ios::out: 文件以输出方式打开(内存数据输出到文件)
. ]# `( B6 u3 O$ |. x- p1 F$ e- \
2 x) ]5 X* K$ q* v" U ios::nocreate: 不建立文件,所以文件不存在时打开失败& u+ n# ^' j3 {, f% M
6 t! y4 k9 J6 s
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
. S( G+ f3 p0 O; M
' F& B; H! n- F3 w ios::trunc: 如果文件存在,把文件长度设为02 `$ u |% A( J: Q5 z
* Y |9 j K' d+ `
可以用“或”把以上属性连接起来,如ios::out|ios::binary& J+ i. I# R% p
/ e0 l' |% t+ O9 O
打开文件的属性取值是:
# u) A, F$ `: { d) S4 Q1 }! a 0 H; x y2 p: h5 d0 x6 |# s( M6 P
0:普通文件,打开访问
: Y0 [8 S; T& \* u- `* ^ 7 u c' c+ _( z/ b" l- ], ~7 @
1:只读文件
$ D% Y) r' U- A
+ B9 f% k. Z" W9 c* {/ c% e' f 2:隐含文件! A( R+ N+ T! L; o
6 y7 W' ^ X6 g& x* y- J/ Y 4:系统文件9 A- {/ Z0 Z, v
; f& B+ E% o1 \' {8 T 可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。- A' h) c s9 \* f) W W/ x
4 O) t L, f/ ]$ }
例如:以二进制输入方式打开文件c:\config.sys
7 K3 z2 C) G5 G! D
+ T, L/ E9 B, v fstream file1;6 X5 v9 w2 E6 f* @
- c7 T6 ]+ L& C" U) z" ]
file1.open("c:\\config.sys",ios::binary|ios::in,0);# s- M) D0 X: z+ `/ U
% k9 r. i4 o2 j 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
+ [- l5 U/ `! n! X 4 ?; l* J/ R; R
file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);% ]' a6 T+ c- _0 K1 A
) t) M, ?' p7 l3 j1 {: Q
另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
' r& b& ^9 O8 A" Y% e [ 6 M% s; Z; j& b" l, W- ~
fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。* P. i6 ^( ]4 s- F/ }" Z3 U
5 A# v \: ]5 x6 x' w! w: N' p5 ^* U2 z ifstream file2("c:\\pdos.def");//以输入方式打开文件
9 }0 r9 d2 A/ V0 {
9 i/ Y, j( i" l" A3 N% T ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
$ |6 l, v1 c' ~& h
/ i0 Q6 `" ~/ x5 N b 二、关闭文件
) v4 P! X% a; J8 x ( P3 P! `7 N/ z, m
打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。
% [6 D1 o) r! b8 [. c6 ]: _
2 P; r9 \/ k1 t! w% p' H% o4 | 三、读写文件/ v4 S; ?. _! ^7 [8 R4 L/ o( D
+ H* C) ~0 v% U5 v9 d
读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
5 `5 `$ s' ]& U# M! ?6 C; b ' `1 C4 j7 @1 W1 f' L
1、文本文件的读写
3 @" ^$ ~" Y8 t3 Q
S, t' ]: p+ b- P 文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:$ D' A% I3 t; |; k
# |8 C1 v$ Z6 o9 O& |' ]# {+ \ file2<<"I Love You";//向文件写入字符串"I Love You"
* ]1 R2 _* u( ?& `4 p8 z% f. @; k
8 J9 P+ i% p. f0 J% r" D. P! D' u: x int i;
" k& ~8 k9 X0 ~' ~0 ]
( p/ G6 r) u' s% z3 [ `4 q file1>>i;//从文件输入一个整数值。
\; g# I( A3 }- w* O
( u9 [9 i$ P; H* s 这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些3 {/ A& q( T+ c% L
2 ]" i) W0 e% ~9 T$ r. f" ]9 | 操纵符 功能 输入/输出% ^8 y, R8 `9 X
, O) d! Z& c0 E6 E* n6 _9 H8 L
dec 格式化为十进制数值数据 输入和输出
, ~2 B, j V- I* C, C
+ K+ q7 Y* j% d0 f endl 输出一个换行符并刷新此流 输出) E) D6 R7 `$ M- {- E
( A) w8 C8 c9 X' p8 ~
ends 输出一个空字符 输出
/ v& P0 b& X! }0 G- o8 u
7 }. l8 X; W F2 i hex 格式化为十六进制数值数据 输入和输出
9 y" l U& Q+ W+ X6 w, q4 ` i; b9 Y& D3 m' A& |3 I! v# J
oct 格式化为八进制数值数据 输入和输出
% _8 X. k4 @8 z5 T9 W9 A; h4 p
1 m- g- e: s- y0 Z9 ?4 B4 g setpxecision(int p) 设置浮点数的精度位数 输出
0 d7 S a% _4 s) {# X) r 1 i2 _" n/ @3 ]6 D. m/ j
比如要把123当作十六进制输出:file1<
; a9 P" N7 |: d/ b4 N 2、二进制文件的读写3 ]% W+ \$ f+ \
\% I8 c" O- `! ~+ V5 ]6 Q
①put()
2 O& b# Z2 f! Y6 Q1 y+ Y
' Q& \8 `2 k) R6 |" ^# _/ w6 F! ?9 f' @ put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
8 @- H1 J! ^+ {' ]# e, R- n' o$ O% E
3 o( p+ E" G+ H) n7 g+ [5 ^4 x ②get()' u$ {' h! {! U# q8 }! S
$ q% p9 l/ X& Z! D9 e
get()函数比较灵活,有3种常用的重载形式:
* a7 X+ ^2 f: A% o* [9 Q * K& M2 x' Y, {$ B N; x% N, S
一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。6 A. P% B$ [/ U: T% z( [
2 p& z+ x( @6 ?- X* b" i 另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
' k4 T' k6 B' M# a/ I/ ~7 Z5 M7 Y$ Z
' b6 P. S9 n* B, M* c 还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:
+ @# {( r' s4 Y8 n3 R6 @ 4 v% [5 i3 d' w8 N& ?0 b
file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。* \$ K5 R9 }: u/ e- M; C
/ f* R. B- ^6 K6 y; q6 {
③读写数据块
+ j0 w/ [2 w; e- a6 ?" [7 o
1 x. f$ R& \- {( v* c 要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:0 z* A6 p$ P& }% d7 m
1 h$ E" [5 i7 }- N; L d
read(unsigned char *buf,int num);2 T; e ?9 f7 `, @9 S
7 u4 W) {" V' C( W+ S write(const unsigned char *buf,int num);, v+ X5 Y! _8 k# w: [) ~+ T' C
. j" Y" u9 z" q2 @4 c. k read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。& e+ s, t; o; R, z' b+ W
, M# f8 I U4 @. o. A 例:. A: Y8 R3 _7 m
, x- J/ F4 k( X3 u* t3 j F unsigned char str1[]="I Love You";) k8 _; y0 ~$ ^3 r3 a6 m
- s9 p; [/ X( e E2 j/ X
int n[5];( E* @* P! I, ]4 s/ H. ^0 t
/ T. D$ o; a1 ?0 a7 @; p8 P2 F
ifstream in("xxx.xxx");
9 H) G; E' {3 q& P1 `, E . v: @' M6 y D# |- V
ofstream out("yyy.yyy");
/ W3 ^* |* D8 Y3 e$ U / ~+ v+ Q# T1 g) U Q! U2 M
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中! \/ J8 v2 ?& r) p
! m% c" i* h; u' d$ O D
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
6 R6 ]- |9 j' n: j0 D% D9 Y1 \ % X; y6 c; q4 L! W& Y5 t9 b5 E
in.close();out.close(); 四、检测EOF0 ~9 D$ f, D; i# [0 X2 A! V! u
4 q9 e: b `: w; l" h 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();) p5 ^4 B1 r) | b9 G
( v l+ u9 p, P; A3 Z 例: if(in.eof()) ShowMessage("已经到达文件尾!");$ N# Q! p o% [- U$ H
6 K3 E: q8 [) W2 D, t) |) \6 { 五、文件定位
) _( c! w: N, t: u# @ % x+ q7 g3 }/ E) `
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
0 s5 V3 g' ]* g" M/ E& d4 E
. o1 f: ]( s& _, l' v% Z/ W istream &seekg(streamoff offset,seek_dir origin);
( Q6 h c& _9 @: O6 g3 O 0 C* i7 ^. ?! E( y
ostream &seekp(streamoff offset,seek_dir origin);8 [: d% X% _" d+ w5 j% y7 J
. t1 R" W% F! `" w; d( |& a% n, S) N streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
5 ?, R4 o3 a1 K( S& }- O' Z1 B! l / O2 R3 b3 U4 o$ |( b8 h6 ~0 t C
ios::beg: 文件开头. u# p3 L- m2 R1 T. q
0 e" [0 Y$ _& O3 E! g3 G. k
ios::cur: 文件当前位置
1 z+ \' b. f& u' }. `# q; m8 R
" g: b7 {0 y2 I- N ios::end: 文件结尾
1 {7 E9 ]) [6 n0 l# Q7 K& p
1 [9 P6 }- d4 }8 E& ^ 这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:
$ a1 U! [; K. J+ M* K9 ]. @
; s( y5 i0 D9 c% E. K9 V file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节& C" H( f3 O& M) ?6 z
! p) `5 `/ ^( l$ m3 K) V file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节 v8 Y# k# N9 F6 b% X
5 ?; _) n2 ?. X7 Y |
|