|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;3 w5 M( ?" j- J7 P; j: a
7 Y/ f n% B2 T0 i3 F- J 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:
+ u r, {* [4 w/ t
3 e" F. B! ?7 D" {: k 1、插入器(<<)
" t; X# `" j8 a6 B# F+ S, F
7 ?7 w; h6 V9 U( ^! J) d0 s 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。" L" }8 o: N* o7 ^. F
$ q( ]1 `; R6 n3 v/ o 2、析取器(>>)
8 \9 b* r1 g: y Y
1 @9 g/ J7 Y: l, ?7 m 从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。" N$ j" L" w" G
0 U ^% H: l0 g 在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。; i+ x' P9 w# L( p6 [
% |9 M2 z) O, q$ ^ ` 一、打开文件
1 R h! `$ k' e4 O+ p% L
m7 ?1 t9 M3 E( t) ^+ M+ v 在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:, s: l9 v' a* u$ Y% o3 k* }0 e. f
4 L& m6 W5 ~5 W8 A* k+ Y5 \% \
void open(const char* filename,int mode,int access);参数:) w0 `# F3 h2 S, d4 j; D, M
8 E& Y/ C0 \0 s# d filename: 要打开的文件名' P! k+ C4 Z B: D1 V4 J
1 ^/ Q3 \$ z2 B( j n
mode: 要打开文件的方式
; r7 q# m. x& s - }, R% @% a5 y. S5 y
access: 打开文件的属性& j' R% g& _% }) v3 x( h6 G' _
% Z8 d9 Y- e4 s; ^& f
打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:
- n$ y; e8 V' z3 {# I% y
* v0 k4 ?4 y! V$ I& g ios::app: 以追加的方式打开文件: R1 m3 p$ @ F" \
7 D Z3 a0 A; ?' ?7 ^9 ~ F ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性; o, S% l/ ^0 J
+ z9 K* ?( [" u+ r8 t
ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文' Y. T8 A- i/ J, Z0 A
! C: C4 W8 g8 H+ Z' k9 e ios::in: 文件以输入方式打开(文件数据输入到内存)
5 U1 N. \/ r3 n+ J5 Z1 ^: N9 }
) H7 N$ E3 h$ z1 } ios::out: 文件以输出方式打开(内存数据输出到文件)
7 E1 q+ j- S3 u
% J2 H i; Y3 z- x. R ios::nocreate: 不建立文件,所以文件不存在时打开失败) d) o& g% B g" a
$ E; Y" A$ B$ S: ~2 _0 c( ?
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败7 @# {0 l% z8 D. I' I: D/ P
6 q# x! j0 N6 I0 R
ios::trunc: 如果文件存在,把文件长度设为0% D4 v! `$ [0 o7 R& t3 V) I
# R- N0 T: a; g' m
可以用“或”把以上属性连接起来,如ios::out|ios::binary6 g& l# |! q1 N3 x3 a' Z
- p0 q. Z7 V& C$ e% M- x+ i 打开文件的属性取值是:
; j' c# A+ X, R1 C7 z
6 M8 _9 x7 H7 B, g* k 0:普通文件,打开访问% K9 y* w0 j8 I, B9 _( O( O5 i* ]
) m! J3 O9 ]# [ 1:只读文件
" H3 F/ e3 L( C4 V0 \7 n1 q6 [ & }( ?! }; I, v) v2 k ~+ P/ A
2:隐含文件( f/ h2 C, K7 J6 K
" }4 n8 O! _: v" @+ M& ` 4:系统文件
# G+ Z& d9 U% _
& ~' P. x/ {3 Z% u' ] 可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。/ l8 a) U' j! ~% N5 d% c( @; F
+ A8 }. {5 Z9 P2 D: M 例如:以二进制输入方式打开文件c:\config.sys
: h6 _' n, L/ g2 E5 L
8 D1 `' f e1 j. Y3 e fstream file1;
- u0 ]( F* o0 {4 H% E" g8 }/ }* {7 o , A$ @/ O2 w# V/ t( T! N- o' }4 F
file1.open("c:\\config.sys",ios::binary|ios::in,0);
; U( c2 G( S8 ?* t0 g7 L, I 1 s, }* M7 }1 ]: z2 l( t. G7 J. N
如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
7 {0 ^2 w& A; u3 E6 _ % a# }( J. s: u
file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);! v+ h) x! M1 e8 M: U
" U& I5 v, n0 Y
另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
0 J) o: a( ?! }0 [3 j
- Z5 S* n' f9 Z: m fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。7 S% x* x' V7 O o
, g5 V) i2 ^! F& S3 u0 K5 A
ifstream file2("c:\\pdos.def");//以输入方式打开文件
4 T! l* W) ^2 _ . O7 T, M% D% B: r6 H# Z
ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。- C; A) l# t* `8 C, J
: J/ N# K% q4 W' N0 j, r 二、关闭文件
# q, x4 t9 f, g$ d+ u, @! L; ^# \. I
4 @0 U7 h# |* U$ g* q! ~ 打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。2 Q; i. Y3 ?7 M; i- D2 y9 [4 r5 a
% }# R* U9 g$ k1 x: Z$ e 三、读写文件
2 p1 G/ f6 e& V% C( T
7 C: W9 p$ `8 [0 [* Q6 L' y 读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
9 _; `! s& ]9 V" X6 }
. N2 K6 Z/ L2 u" Z8 I 1、文本文件的读写9 x2 X+ r! p7 ` u+ `' O
6 M A( ^* ?% s3 S$ p$ u4 o! ? 文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:7 @# t& k1 H; G; N6 a6 j
6 I1 U& l- ^8 H9 T# s file2<<"I Love You";//向文件写入字符串"I Love You"( W* }* i0 v1 `3 `/ ?, x
# ?( X/ [; V" b- \7 ^4 `/ ~5 t$ _' `
int i;
& P; c8 f4 ^! v
5 r. Q! P. i U/ k) W4 M file1>>i;//从文件输入一个整数值。
0 @ ~0 J' D. K+ G4 D- E
1 Y$ j1 l$ ^6 _' I/ v4 R, {: i k 这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些- x: R$ N' z V, K) l7 y" c+ Z
" L; n+ J4 l) o, r3 K* c) `) A8 n
操纵符 功能 输入/输出, \- ^ I6 g5 D7 u- ?
/ g3 Q U4 a* W4 ~ dec 格式化为十进制数值数据 输入和输出
* b" V# M& E1 Y" I
& E- I" ?1 _8 Q% \: ^2 ~0 K endl 输出一个换行符并刷新此流 输出1 H* K7 S& B- ^! O4 t
2 m5 ^- A8 T8 P& H+ C8 M7 T ends 输出一个空字符 输出
[" i# H3 V! F" ~( e
9 z& \) W5 g% O' _ hex 格式化为十六进制数值数据 输入和输出! u% A: ` A2 _, M' w- X
7 G/ [( M2 N9 f6 N4 V oct 格式化为八进制数值数据 输入和输出; b- h" C7 T3 y3 h* M2 G: _
, ?4 L/ P( J# k+ x
setpxecision(int p) 设置浮点数的精度位数 输出
+ d4 [6 `& N/ K2 Y9 l
' `. E; b+ z, }8 d, h; L+ n! K 比如要把123当作十六进制输出:file1<
1 ^8 a" Y' P% _: `7 @: r* u8 V6 X 2、二进制文件的读写
, X5 m/ }1 [3 E8 B6 U& f8 K & l* Y4 u: A z5 B( e
①put()
8 a" p' \/ B* R* H- m$ e9 l 4 Z3 |* L/ B" m+ I$ Z* }4 B
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
4 Q3 Q' z; L, G& ]* Z( d9 q
. `( b5 ~$ f3 g/ e1 J' b! q ②get()4 R- r) Y- I) c8 n Y1 a
/ e, ?8 P+ H U0 C& s/ J; e; ` get()函数比较灵活,有3种常用的重载形式:6 V! `5 h" z4 z
# r. G+ {* e$ }$ X) K8 x. E 一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。* n5 ~8 @* ~3 W/ h9 }
) f* I$ U2 f8 O; n% p1 W
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
3 z6 D2 ~+ t+ v9 Q+ s4 i7 }
. e9 @% N4 P/ N% ?6 J) B1 P/ H 还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:
6 u3 c. Q. E8 {; y
# J6 ^, ^ f6 m5 k9 K% `9 T5 q file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。
0 p, {3 G5 y/ I- w+ @) f+ O
. K1 {; _/ a+ ^- u( A! r ③读写数据块7 v! ]# U4 A7 _: U3 l
0 \4 v% A8 Y# X3 D0 K9 R 要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:1 | s# ]9 H! R1 @
" |8 P0 g- F& c3 l read(unsigned char *buf,int num);& G; x H! R' F+ z! l- h
9 q$ `: E; K6 z; n, E& H write(const unsigned char *buf,int num);
+ g7 E* U+ f$ D: S) ^" J- L 8 g, {3 j& S0 ^$ P& F1 l
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。
" v6 K" d( Z/ }: v/ P7 `
- J3 A! D1 {# N- c# V9 B' _" v 例:6 W2 l* s, z1 H5 {0 Z
% z* D, v; o+ @: P+ ?( }' c unsigned char str1[]="I Love You"; I0 c5 [& f1 H9 U/ |6 d' O [
6 q& ~& M% U. a; h7 n2 p
int n[5];5 n( T# v" P( @. d. Y; |
% }$ I; Y; B! `1 ~! F: }
ifstream in("xxx.xxx");
, D# X$ ~2 L! k& K
! {: T7 L. O9 c! a# o, }7 } ofstream out("yyy.yyy");3 b) ?! Q. @) B- q
) g1 l# l( g" c0 B1 L( \+ _+ L out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
7 r- Z: \% [. ?9 K+ x, P
+ m, Z; z, h0 ^" @' Y; g% j in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换% }: H" u; `+ b# F. {
; ]' G5 d3 Q" D4 [. O, O
in.close();out.close(); 四、检测EOF
5 }, o8 \! q0 T* ^% ? & h* h& l6 g% P. S2 G( \ i
成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
1 _6 k1 I! P: |& d. v+ v ' {+ d8 q7 y& E, K4 y
例: if(in.eof()) ShowMessage("已经到达文件尾!");
/ Y [2 a& l, m . V, ~7 Y' M/ r0 y8 e1 N
五、文件定位
. o9 S+ q: R5 p7 E- i; b + I6 g1 P) L9 w! u# b7 ?
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
& \6 m2 r O/ X: t$ u + j# b2 i3 A+ o# O1 F
istream &seekg(streamoff offset,seek_dir origin);" n0 ]2 m2 v. F
: a! F4 t3 Y3 w b+ }/ p' j ostream &seekp(streamoff offset,seek_dir origin);
$ |& \8 B" z2 v
9 M6 W2 c8 `) o. m p2 s/ K0 m streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
5 T7 r# [' q( O% K 3 X) ^5 S0 U) w/ o9 d" f! {
ios::beg: 文件开头
- n& c. b8 O: R4 F. T% [ 2 I, B! D0 f% A# W+ K( p1 o
ios::cur: 文件当前位置 J* i) f- V6 v; _( ^
6 _% H9 t5 [7 v$ g& q. G6 @# ]
ios::end: 文件结尾6 U$ K" f, `! k" e8 W; |7 J
3 h8 J; ~6 i, D. h, x/ w* Q 这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:
" b" y6 J# C( D8 e " M4 I: p& f2 ] R- r2 Q! e
file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节9 M& l* n# r# H3 i% c5 p
0 M) u1 p; B$ W
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
( L) F* ]: `% w
7 W# {! d5 E' V5 @) t |
|