|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;
^1 m2 k& |0 m; @
Q) k: U- t! h) H: c4 V* \/ ^ 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:
% ]# I; E( I+ @& P 0 V9 ?0 N+ G0 R- _' O! q. e3 u( r
1、插入器(<<)
z7 O. e' H* W6 x
- c7 t2 {6 a; W# j 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。) L; y$ i9 d% e, s8 d9 J1 [+ T. B- t
7 }' t- @" I. F$ h7 p! R 2、析取器(>>)
; m! j$ H3 K/ h $ F! P# Q1 o4 O! @
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。: ~) Z, z C* ?$ m
1 R7 E, E! q9 Y. a. x( |; |; x& Q* y 在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。
+ K, }) `' C* _9 x; P 4 E* q1 f3 r2 Y" x% v$ s/ X
一、打开文件2 ~8 ]* @2 O# X( p6 g* T( z
$ N. X9 l) }2 c, ?6 L
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:
& ^1 S) f+ M7 F' C0 N3 A) i3 s1 @ ) N, l5 T7 E5 r
void open(const char* filename,int mode,int access);参数:
4 M. p. {' Y2 Q& q1 R 2 U$ I0 v: D5 z+ y9 j$ U
filename: 要打开的文件名
' }8 Q/ [! e* ^, z3 e) D + D r/ m4 J8 d5 ~+ g, K
mode: 要打开文件的方式& b9 K4 H+ x, T/ j' { }0 v# j5 Z
/ L. M& ^* b7 L n; j access: 打开文件的属性8 b6 S. O- L+ p: f) d
! b7 ]8 H$ `( @2 }5 a% } 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:% Q6 ^$ ~1 V1 n5 B0 f5 K6 f
' X5 P' h1 j' u. A/ s# a) p
ios::app: 以追加的方式打开文件
; O* ^7 B) P( T0 S2 m
# _% G+ o. E' _: } ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性% v, P4 d6 r0 p/ \) H4 u
2 \( p3 P! K5 p' s8 ~ ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文
/ @ w( J' y) ]
+ t% {: k9 @/ p+ a j. x ios::in: 文件以输入方式打开(文件数据输入到内存)3 g- k0 p- p" D- `* N( J& v. k
$ V8 p; f, B' }, M ios::out: 文件以输出方式打开(内存数据输出到文件)8 G( q1 }9 ^% f0 K$ I) n
% M: J0 {- h2 ?- a5 A9 ^ ios::nocreate: 不建立文件,所以文件不存在时打开失败$ ?, Y% r ?! D9 q+ n
I! n% i% \) l/ k; c/ H
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
2 x$ M: N' r5 u% `: C& O; u2 g" R 7 ?1 a8 I' ^/ y/ s% D' Z
ios::trunc: 如果文件存在,把文件长度设为0: H9 Q; Y3 C9 L U! d
( K7 L- H! f$ a9 v1 {* w 可以用“或”把以上属性连接起来,如ios::out|ios::binary; B; s0 o$ H9 R
: G6 F' c O2 E5 ]! O
打开文件的属性取值是:$ U1 ]9 g) D5 A2 C. r9 ?& i
. ~4 [8 p, W; A5 L
0:普通文件,打开访问
( h) U" e G6 r. _" K
" [" Q+ n4 d5 v+ g 1:只读文件
- H' b) v! k; D
0 N7 s8 q. x7 L 2:隐含文件, `* ^' f! D H; _4 h7 _3 z" K5 p
% k6 {- q, ]3 A7 S
4:系统文件
9 \7 x% H/ f1 c
, C; H/ R! k" `6 e 可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。& n! Y5 p' g5 e" m. V0 c3 j1 e3 X" O
( v% y3 _, O0 k9 k5 y/ i
例如:以二进制输入方式打开文件c:\config.sys
1 ]$ x ?) n, a / j# b7 t- i. J4 U
fstream file1;
. r2 L6 v# M6 ] 3 p9 x3 Q* N) r( b! s
file1.open("c:\\config.sys",ios::binary|ios::in,0);
& s' z* z6 H9 x5 [7 ?) H& z/ s4 P
' @3 u z3 A( |: q 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
0 ?& y! ^, M8 ?5 B7 G+ y 7 j4 d0 o y! @# \. w
file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);$ E; _0 {5 n# S- x
. V4 v0 u# M5 _0 L1 e% q
另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:: _4 N- E, e/ V0 a4 x
0 I4 h# W: F( ]% s! [/ ^+ }% F fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
3 x# [9 B. x G% v; V2 y/ q/ k 0 V, _# T% |) f% {- u+ y& X
ifstream file2("c:\\pdos.def");//以输入方式打开文件
+ B6 S' I4 I7 A& V2 G
1 P3 a+ R; u. t$ t- r! Z" y" o& | ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
3 l9 f- {* X: N1 s8 b 0 [! s/ l0 Z) ]' j: \
二、关闭文件
* B" R# U4 ^+ d% {0 M 1 i8 p' i/ j. L5 Q2 z0 l
打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。9 G6 ~0 V5 C' t# R
t P1 _, t. f4 u 三、读写文件
% m- c! Q) E1 j: p% @2 C4 s
+ @4 r: q* t$ ]5 Q, h0 t# R/ Y 读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
2 \9 \6 x# Z- {/ b1 k/ }" m ! e% n# W4 x& E7 M
1、文本文件的读写; j$ q+ ^6 E- |
: U3 {" ^0 }, O9 }2 m1 Q
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:
5 B, ?0 Y6 C# t
( e( a2 D& ? j4 E3 {+ Y0 J file2<<"I Love You";//向文件写入字符串"I Love You") R4 h) x% c- F% S* c+ L& H9 A
) t7 Z; p+ L0 K/ i$ R6 r int i;
( E l/ ]1 `9 k2 p- v' O# V9 W
3 ]) I8 u3 b+ I* S: Q9 I m" a file1>>i;//从文件输入一个整数值。
3 c$ ~5 j, g1 A3 c0 Q C ! G$ V& @) V4 d7 Q
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
$ v; u8 `+ d! @+ u7 a( P 4 o# Y8 b2 S9 w) }) I9 u
操纵符 功能 输入/输出
0 ~# l9 C' U* |3 ?
, @" i" @' r* I- K S dec 格式化为十进制数值数据 输入和输出# o& w% @6 e, O: m* w# q! D
' D% V4 z s2 c6 F, z" M! v: s
endl 输出一个换行符并刷新此流 输出
' N) y1 `- s' }; z: \5 C0 p; J 9 S7 h% u3 _+ p3 q/ H0 y3 A
ends 输出一个空字符 输出
: ?7 h' z; H: s2 }4 x0 Y$ ~
$ g! }) i7 V9 P3 E" E hex 格式化为十六进制数值数据 输入和输出2 _7 A5 `2 l P* w9 s* ^7 B q
3 C2 p7 \: P% K9 U$ s* U, l
oct 格式化为八进制数值数据 输入和输出
- ^+ A7 t0 R6 I/ K) D% S) g 9 G: H2 Q5 {2 I4 N
setpxecision(int p) 设置浮点数的精度位数 输出
+ [5 [6 g6 }0 w ; ?, P. K* p" K# k
比如要把123当作十六进制输出:file1<
/ t6 i7 K9 E6 ?1 F: l( q ?1 \7 \" v 2、二进制文件的读写5 ]' q0 O- h$ y8 E& d! [; h2 D, E
/ q, Y& S% c* U7 P B ①put(), u2 E1 D5 G& c9 V, h4 ]. ^
; K8 B/ Y0 l: G put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
$ Z" W5 `) g/ G' j$ H) S
+ q4 e; {- X/ t/ S) {4 b ②get()! C, V/ o, `) S: i* e
0 t1 C5 R6 c& {( S [- d get()函数比较灵活,有3种常用的重载形式:& H# j0 H; V" N* A# o# {- Q
7 w! E" V; c& l, T 一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。. K/ I1 C3 J# Z# t3 \1 ^! V
8 N: z& R* G( d/ @( c8 l9 x
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。& r1 y9 G! `- U6 l
4 ~) R- f n/ h 还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:9 ~/ {% e3 g( F& Q/ G
$ Z$ P3 b4 q9 [% z" q
file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。% a. T% K! k/ ]1 Z! b
. {% @) l& L; W* r. v: B' s
③读写数据块
' p* l* o8 Z( b' _: H: S* g 8 i! N# z" q/ G4 e- @
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:% u/ ~- C4 Y$ [
* Z; D* V5 ^; `5 K* u; H7 c _ read(unsigned char *buf,int num);8 t" u. P/ @$ j7 L# w
C' Y) ^' P' b# W0 Y. Z write(const unsigned char *buf,int num);; p; m+ h) I; |) L5 |/ N
9 i1 F+ T5 r! N, _4 `* H read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。( g! H/ R% |: M1 V4 t& j- H
: u% p/ ^0 q& H
例:' V$ i+ R0 y% v' w" p
5 v+ C0 s }% H# [4 m; h unsigned char str1[]="I Love You";
8 }! _# i: R$ P% Q % f O2 l) P0 l6 z
int n[5];- w& M. C) K9 X3 e5 u
( x4 A% ~: S$ y ifstream in("xxx.xxx");" W$ y/ C4 e X5 v* `& p9 n# `/ Y
`. U6 Q& u: N( |# G* v ofstream out("yyy.yyy");
; {6 \& A8 x& k* q) {
! k# Y! h) Q6 i z- D1 E f out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
: D6 g" ^7 @% a5 h! @ n & B: g g a" U' \
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换/ H7 e( `3 N3 K- s7 f
% I0 L$ `" ^5 J6 b& I
in.close();out.close(); 四、检测EOF
0 U, a3 @9 f+ k' l; h6 ^ [
+ r) |' ?/ o$ b5 m1 v* T( s7 }3 H 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
( K% x0 M5 o1 w; x* p4 A+ b ' R* e: N$ V( k4 j
例: if(in.eof()) ShowMessage("已经到达文件尾!");$ G& G8 a+ b- r O" U R3 @+ d5 z- A
7 r9 [- F4 k* [& H) W! B, K4 T 五、文件定位/ a4 x# N& `6 f6 R
9 l& T# G/ ?( V+ {# k* e( ^
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:5 ^6 L4 s5 K/ I- v- N7 H
# |' y- E& s; i/ }
istream &seekg(streamoff offset,seek_dir origin);
, |7 P" q" a$ H
( S* F9 e; h, a ostream &seekp(streamoff offset,seek_dir origin);
5 G: U& Q% K5 j+ m
) |. k# {* M8 v! Y; i( Z) p/ r streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:1 Y2 a$ O" U2 F! j$ x$ o; p% l. u# F
7 |; j d9 }% O1 P5 m# d
ios::beg: 文件开头
9 X6 u4 \& S& P; I4 ]9 ?* I ' i; |, K* P; l+ J( k( W
ios::cur: 文件当前位置; ]! \" j" C4 l! G# d* H
" ^: x! ~6 l+ c) a2 Q# Z8 ^ ios::end: 文件结尾# l3 \* j) G7 } V
: C! ~0 j( o! d5 u
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:
! p* E$ A! K$ v( f. C' V7 x# s e' `; V9 p) I7 V) G& p
file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节2 X" `& L/ L) e, s, }! N5 D" F
3 T- S: |7 p7 D& _! l file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
/ C! k1 s; a* @% j2 u. v% ]2 A) d/ N6 ^8 }
|
|