|
|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
×
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;- K, m! z$ M) _$ |, G7 M
3 n; h- j) M0 b9 I3 R: C
在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:, l( Y0 B- g& h9 w5 ~ m& F
+ j1 ~( Y2 w, v 1、插入器(<<)! C5 k+ m2 ]2 ?( ]8 ^! z
# Y( B0 l! y/ g* L1 Q6 l' Z 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。
' ~$ j( F0 }! s& E8 C V6 ~* a" O( _+ |& o$ E
2、析取器(>>)7 ?3 Z0 _: a1 i" M2 ^. k7 `9 | i
8 C. q' m" W I: M- Z0 _
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。4 I- \9 w! p5 v
1 j& x9 c: j6 S: y5 x" k
在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。
/ f r( e) w2 O4 w2 `6 r
) }+ v# j* P1 v! J. T& K f5 s4 y 一、打开文件6 G# t2 P3 g* \- p. M+ G3 _
/ l) c- q, q4 X
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:
4 m5 |/ L9 W& K 3 \# R% r! q/ d( Q' Q' Z3 p" G, Y) D
void open(const char* filename,int mode,int access);参数:4 d3 P @* U0 N
/ [5 { w+ d3 t: C4 d3 r
filename: 要打开的文件名" A2 M1 a% @3 R e
# |8 u6 Z- k @7 n, r mode: 要打开文件的方式0 T2 `7 @! B4 h- G* D
/ e- T e# R) S. h
access: 打开文件的属性# n4 A7 r( `8 k$ {$ [% W( r
0 c; u3 n- Y* s9 `4 X/ t# l) z 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:1 R+ _7 h( C# W# y4 G: k0 e
! v! W2 y( D/ o. f
ios::app: 以追加的方式打开文件0 ]" f# p6 x- V, F T/ L2 S
4 W, A; c; A. c& n. K9 x9 w
ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性5 l( E. y4 x) {$ o3 M% ]$ d. H
( b( W$ i5 |( F i/ K, m# ` y
ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文
1 Y: M2 B% f4 J* B1 r
) H, ^3 `6 y% z) b ios::in: 文件以输入方式打开(文件数据输入到内存) f! b6 w" X6 i* ^5 R+ b
4 F/ @! ]+ p6 W0 P+ z4 j ios::out: 文件以输出方式打开(内存数据输出到文件)
7 ]5 [) R3 ^# K* [- J y/ B7 v+ ~9 E
7 I' j, O2 v9 I0 [# @) k& g ios::nocreate: 不建立文件,所以文件不存在时打开失败" }( o' S5 z N5 }1 w
2 ]' v* i+ [% @. |
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败1 r. H4 U; R3 E, q8 O$ }# D
6 |; }4 T0 `" B6 ~/ n! U
ios::trunc: 如果文件存在,把文件长度设为0
" A j1 y& ~" O% j8 K
! D& S1 d2 }/ M1 i: R3 R, Y% W 可以用“或”把以上属性连接起来,如ios::out|ios::binary$ t$ L" f1 U+ \1 \ H0 Z
. r# h' B, G/ W" ?3 ` 打开文件的属性取值是:
% Z5 f% K' t, y& Z; K
5 S0 C2 \0 M; k 0:普通文件,打开访问
5 q. P' n+ w$ f6 x1 j
8 f) b: t ]& c+ g( l# B* d6 s7 A 1:只读文件
! x' y, b. ^2 ]5 \! Z0 y # q& i5 b$ [, z4 E8 Z
2:隐含文件
. M7 r) K0 l& [ : p. p0 _5 T O1 K1 v( J
4:系统文件
" R) m- A. m4 {8 `: T! y1 s
0 V! n \# k5 { 可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。+ I) V& w8 e' H$ \
# z4 G! A0 ], T3 W- m: O
例如:以二进制输入方式打开文件c:\config.sys0 c. ~' {' d; t) b
; V/ z' V( k& v! n fstream file1;$ s k- }/ O% F& G1 A
% a- i1 t2 a2 |! g/ }
file1.open("c:\\config.sys",ios::binary|ios::in,0);7 T& N. R0 d! D) w3 @
% J- Z, ]. ~) M5 ^" a6 X3 l; m9 U
如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:0 n7 n/ U) W% e: s: ^
- v x3 j8 K; h) ~
file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);" ?: V& ] @' h
1 r1 e3 _! l; O$ E, Q" j 另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
! @! u6 p4 {1 Z$ g9 l " M; f8 ]- [( [$ u$ u9 }$ ]7 t4 U
fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
9 ^3 Z0 ^! N. ~ y! L + q& Y. |' y3 [* F, g
ifstream file2("c:\\pdos.def");//以输入方式打开文件
Y2 V! f/ O5 E 8 z/ Z6 X7 r% U) k( z' X) P4 z. h
ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。3 O. L( g, d d* x1 |1 d6 G
0 ~# W0 G0 x5 g) X& P7 j 二、关闭文件
% P; C$ M- J4 R( T# e, Y/ h
- l' r' @: G9 l 打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。
* G4 t9 d0 c/ X. ~: U- {
0 e9 W5 m2 j; | s0 o 三、读写文件! Y8 P9 N# E' U
' P1 J% H: X5 i1 C( u 读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
, p4 l9 I1 U+ v+ a- L
) z9 L4 m/ S3 P 1、文本文件的读写
$ b' P$ g" ?- G& l' M" b) N
9 k; x# x) D Y( X 文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:
4 z* A+ q; {0 g3 j& N; [/ }5 Z
) s! D# q' Q$ |. O! d4 i file2<<"I Love You";//向文件写入字符串"I Love You"4 p; P _2 o( | H2 P" I' f' W
# i3 y' O- }- p/ O# b2 D int i;
) @/ I8 H2 n$ i2 j
& J U( K& \4 M( K! _' @9 C7 C file1>>i;//从文件输入一个整数值。% p" N% g( r7 U0 w/ T$ P
3 o, x" M, p; O/ A 这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些8 n# x2 Y0 i/ m8 Y3 D+ l7 G+ b
" I U" J+ [1 u/ L( V; u 操纵符 功能 输入/输出
' `9 H- J6 G1 T p6 @
* [+ u c2 t1 s* M# j# h dec 格式化为十进制数值数据 输入和输出' k* E' n4 H0 O/ A! a
) Q5 q! k5 _5 u
endl 输出一个换行符并刷新此流 输出
4 w- n& I( y% l' c& S/ i
2 L" q, j( _) @$ i ends 输出一个空字符 输出
. o8 [ ]( ?; @8 j7 J4 W s
+ f/ y. P; i/ } hex 格式化为十六进制数值数据 输入和输出
7 \7 R6 H& |* r) W# K, h3 p- c
, x) `/ s3 {( ` oct 格式化为八进制数值数据 输入和输出
# J/ [/ ~( M+ ~7 D
* ^" W3 [7 S0 G q1 k setpxecision(int p) 设置浮点数的精度位数 输出
( x2 y) ?' h, D( `* M4 Z6 q ; G$ @- g$ k0 k$ ^- t
比如要把123当作十六进制输出:file1<& ~9 }- T7 ]7 a; U
2、二进制文件的读写4 {# M+ |* g% t5 Q* h5 e5 @
# o$ z! t' j( k' ]+ o# i ①put()" m% A* K) b# g u# N4 R
! K: g: k8 S& _1 @. w put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。8 V+ y& q9 R: q, d
. m2 g! t, n1 S( N$ S
②get()6 j0 ?. }; c' e; V7 U' \+ G% @/ R
* z* h" B' L% S0 y4 ~: s5 c# M
get()函数比较灵活,有3种常用的重载形式:
" w% t2 y5 F& s
+ l4 Q2 f1 E) e& g6 L& [ 一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
8 m& c. _ i# B/ i! `2 C: o- s' Y7 _ 6 [5 t) _* y$ @ J$ v$ B
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。2 t) d4 r# ?+ C/ A$ n+ C
/ Z# f. {5 n9 G J# N) }5 b 还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:
; v0 p9 A2 b/ O0 u, S
, d! {7 F6 O6 k! a file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。 a0 X; F( V# z7 t
\! e6 p- G `% e ③读写数据块% T0 D# a1 Z a o6 T7 x- p- f
$ }6 q0 W) a9 d0 w$ w3 d0 i% @ 要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:
; A6 ?8 |5 f* D3 G" ^0 g7 o. S/ W
* ]8 v c1 O- Z! O( e3 p }& H read(unsigned char *buf,int num);
- X }& H( @- ?. c' R4 ?7 t# @ ( B- `" E" Y. |. E) N6 d; r! M
write(const unsigned char *buf,int num);
) r' w5 ?: E- I3 I& m ^
/ q8 Y5 I9 U8 [6 K1 E8 D4 Z read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。
9 v% k5 g- I8 \, W9 j0 k 7 |) Z, ^) k G
例:* F& l5 g8 B. l) h/ a6 H2 F
- ]# U" }9 @: m, v v unsigned char str1[]="I Love You";& e. p2 \% T9 f1 H5 o% ]
- G+ L4 z8 w/ R$ |
int n[5];/ Q$ r F" G1 t" ]4 c
# n3 R- v- [9 I) c! }* N ifstream in("xxx.xxx");
- M& |3 P' z0 [9 L7 D; c7 U' b
' X0 W. t- v* V ofstream out("yyy.yyy");- s; P8 ?- J; n3 B( F
5 D. d% |3 b O5 v/ w; P out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
/ r( L6 b7 [; o z% q
1 C' ^5 F9 L/ ]* o/ }, Y7 V" O* ~ in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换: e+ `+ W5 H; e1 t' `. `1 g# \
: Z/ p$ h6 l# z' a4 R) X in.close();out.close(); 四、检测EOF
' J# E T( s( }
4 L: ]6 B. p5 {9 G 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();* s, F! e7 F/ W% X) e- p) X+ i$ _- K
" L J7 f9 J8 G% [+ w; @' @( I6 o 例: if(in.eof()) ShowMessage("已经到达文件尾!");, I5 w1 K( K8 V6 }2 J4 Q6 T- O
# W% H7 V% r6 L! O$ z1 G: c
五、文件定位
" s a3 ?( Q& J+ I: | | 0 D$ W1 R! w0 s0 B i
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:5 G5 Q1 Z1 h- V+ _
3 J& A0 |" ^2 i' _
istream &seekg(streamoff offset,seek_dir origin);
3 u! q. P& [8 Z0 b8 y
3 H9 I& k8 n& v0 k, N ostream &seekp(streamoff offset,seek_dir origin);
7 C+ B2 Z5 q/ f6 q" r! j" T! U
* s" \* j3 L& v8 @9 f+ h0 w& C( W streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
9 U5 k/ g C2 R, S/ A& X - ]. X& V6 t1 r6 q
ios::beg: 文件开头1 s. L. u# s/ u- b# s0 d
& y9 X! n {+ e8 D ios::cur: 文件当前位置& q( z4 a5 l, Q, c1 A
2 k0 w7 C, ?/ H0 b+ d ios::end: 文件结尾 B! g+ s4 F0 y2 j- ~
% c; F5 s0 f1 a1 I! S+ Y& ] 这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:) n; z$ Z1 x/ i3 {0 r3 B
2 X7 _: B/ a3 U+ g2 b file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节. X* t$ T/ {+ d
6 F& Y# t# Y- i! U$ [( E9 g6 e. d
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
. k; ^/ Z: \. s; _0 |5 G% z& m0 m A% x# x: G
|
|