|
|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;# I. ` X4 f6 |$ {3 J' f
- ]) u5 E# R! k0 G; m 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:5 C3 ^5 f$ m% W" A' m
0 r9 _9 l4 d2 E t 1、插入器(<<)$ U2 d5 ^8 Z# O% ?9 i6 p4 \: C3 K* y
6 m1 j6 ]& ], L6 C& S
向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。. c& p. M, H" \5 e6 R% t# S0 o
9 W$ W" W0 K; H! W* R 2、析取器(>>)
6 }" ?/ E( d3 ?% p) Q/ h0 Z: u 9 ^6 o+ l8 M7 A) H$ Z+ W$ t. @
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。* J8 P% M; e8 d) `7 _0 {
/ L+ X1 s- D6 R4 o% I7 u, Z6 O
在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。( I) U+ ?& e l% m& M- ^; ?: A
" r0 B7 r! e* K, G" G4 ?
一、打开文件, I- J# K4 i' {& \/ w$ ?, q" G' K
" n9 [: f! W( \7 N3 e- i; | 在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:
% r4 |6 R2 X' \2 p8 ? " F* t& ?* s C3 Z$ | o( v
void open(const char* filename,int mode,int access);参数:
. U8 x5 Q9 y6 N$ q. {) U6 e+ A / ?9 s" E7 I- d) J5 |8 D4 L% Z
filename: 要打开的文件名
2 G; k1 Y4 j8 e- r- t5 A 1 e. x- R. d5 R1 K, `7 m
mode: 要打开文件的方式1 v1 v3 @$ a z; D4 {$ l2 R% g
; W/ t& G6 @, n8 ? access: 打开文件的属性& M+ L# L' I* y/ y
8 R- I7 N2 g8 \5 h 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:
# g5 L* `& `+ {( d # ]2 ~+ ]& Q) ^
ios::app: 以追加的方式打开文件) ^, w8 p' B& x& F8 R; h
5 ~: `3 t0 m- r4 _* u, | ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性$ ~3 H& B2 P8 M: M# H- l) W/ d
5 t* r4 r a5 d/ D4 J/ G# { ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文# Q2 A: M. H, `5 S) Y
' \# |5 p/ J `6 R
ios::in: 文件以输入方式打开(文件数据输入到内存)$ N3 o+ q! F6 l" f
. u0 `1 F+ _5 T ios::out: 文件以输出方式打开(内存数据输出到文件): f0 F8 ]/ u) e z" ~7 s
' J' w/ h3 U. J& q' Z ios::nocreate: 不建立文件,所以文件不存在时打开失败
$ W) m6 B |6 U4 `4 g. c9 F ^ 3 }( a& I0 ^, t" E
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
/ w% H' }' T, a+ f0 ] 1 H4 c5 |5 W4 t, G; p/ ~
ios::trunc: 如果文件存在,把文件长度设为0& F" F; L+ o7 a# c# s2 C! y
1 x5 z5 ]- \; M6 j6 r4 P
可以用“或”把以上属性连接起来,如ios::out|ios::binary
4 j- t+ U( k/ o5 ~$ L8 y
" k: m m' L9 _- J R! ` 打开文件的属性取值是:
- v! c5 y+ `1 M' F2 l+ U/ A
" h7 I) ?; q5 v: N 0:普通文件,打开访问
: V+ Z9 N& l2 Y `" R" m& P 6 t5 Y9 Z6 R( ~- y
1:只读文件
# T! S# [6 n( c; Y' L # G$ [$ | y. g" N: L, ~+ C9 [
2:隐含文件
& r& D* H3 M8 ^- D( k/ }0 V4 K 3 H/ F( h N* d0 p
4:系统文件
( M M0 o) b# L3 `6 y, w
+ }5 g' r2 C8 ?. [+ E+ g 可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。- o; I( y! r8 V
# \8 Q3 H1 h# Q6 k 例如:以二进制输入方式打开文件c:\config.sys
3 h9 U; q! j+ b/ M& f& A! q
$ ?$ _0 P5 `, p fstream file1;5 L' S" _" C0 a R7 J/ g5 U. i
( o- S. J7 S0 K& \' e2 Y file1.open("c:\\config.sys",ios::binary|ios::in,0);
; t) q5 R- M; u) E6 e
' x* Y, H, ]) r$ j 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
; u- U! y* ~ ?9 C$ \! `7 {
9 f. b: r3 l- U( M* @7 `' F file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);- Y8 _( m" I' U1 r8 y# N G
: V/ w# A: l v' N
另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
5 [' s# m% t8 K$ K2 Z- w1 A4 `' X 7 a# m3 B7 z, s& E1 K5 V8 E
fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
# a2 X O! h5 r( h8 U) ^' d ! i& W8 f, A5 ]9 A& n- D: H, _+ q9 X
ifstream file2("c:\\pdos.def");//以输入方式打开文件
( u# V) |; K- Y; R9 K
8 [: `, y" ]; w2 E& f ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
/ p' }# }0 p8 a3 V# |
3 e, v; B- W( B" Z! ~+ j 二、关闭文件& N* I0 G7 i$ v. X2 B! j% O
$ S9 E c, J* s3 c4 g: U3 ]" k8 h
打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。, Q' ?8 ?$ H0 N7 l% \- d7 h, m! Q# z
1 N2 f# D) K) a+ O& X; _ 三、读写文件
: J# q0 X% A( | * v* s) \( _* c" k
读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式* _2 _3 o o. S* e
. r# J8 F5 c! V+ t& ~$ q% n 1、文本文件的读写
# S/ s7 ~7 V' L 1 a. @- y( ^! ^) H9 ^( w3 a/ A ]
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:: G4 V9 b/ u3 y" q& {
" i- |4 ^5 \3 d- a7 P2 N
file2<<"I Love You";//向文件写入字符串"I Love You"% \; l9 U. W3 u1 W+ I# m |
: M2 L2 ]" }0 ]: C- J int i;
8 D8 [5 N2 a: e2 G/ H4 d
8 ?- _# h6 n2 }9 l) I) n file1>>i;//从文件输入一个整数值。! F5 m. N+ f, U& \/ }- m
8 q& o& K' J7 y6 K
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
3 W2 X2 `. a; O7 ]" u( b
1 A7 C: S- v2 C+ Z) n2 V" R 操纵符 功能 输入/输出+ X/ l1 d% Y1 o/ {( u" ~: h% [% N
+ {5 Y- t* A" }& y) Q. `: ? dec 格式化为十进制数值数据 输入和输出8 _6 a# J9 ^) e
% [9 p e* m s3 y endl 输出一个换行符并刷新此流 输出
- i) Z+ `. q4 }1 m" G
+ N# g5 C- E$ D' E$ ]& F7 y) a ends 输出一个空字符 输出6 K; g- l/ {: c: L% S7 w6 i
! J/ z/ M/ M q6 M0 u5 k+ N hex 格式化为十六进制数值数据 输入和输出
/ X' I+ P( Q" L$ ^6 |; U. m
/ P$ K6 s* G# C/ ^& L oct 格式化为八进制数值数据 输入和输出. O* X. j; \/ |4 T/ y& u, g
3 t% z3 e2 m9 A setpxecision(int p) 设置浮点数的精度位数 输出
* m! H2 O( J. Z5 I& T+ j2 Z $ D; N3 H% K/ k3 X: h7 Z" d* v2 v7 i
比如要把123当作十六进制输出:file1<+ q# @- M8 G( s+ D6 s
2、二进制文件的读写
3 y# P9 H9 @, _: ^) W9 C # [, V4 Y& H0 B. @
①put()
/ {7 s9 i# l8 }! B$ j5 N2 E $ v; H( ]% X# } ?
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
& \3 X: u( v$ O0 l" M+ `+ e, x6 b
, O1 Q* r; M# p ②get()* F0 v, m! I3 a5 W# [ v
$ i: ~5 A0 c" V: i0 n8 @$ D
get()函数比较灵活,有3种常用的重载形式:
2 q( v0 G M/ Z, U& J
% a6 |; g8 @+ }1 B! S3 W" o% P 一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。) k6 N D# W" J5 c( W
" O* N6 K5 n: z l 另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。5 e" \0 B2 O) z+ P3 w
9 C! ?8 m, h0 m6 D5 Q2 m4 s
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:8 G, A: ]7 X! _* q A
# l& W1 L4 |; n( P2 z0 P file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。
4 I; e9 y4 m2 v
# N) j" B& X2 B" k ③读写数据块% `" W r ?" }
. t, H7 m; P8 p9 @
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:0 Q- O5 X' w# b
2 E3 p* i; ~6 @# H read(unsigned char *buf,int num);( W& I4 |( ^! t/ S
' [ |0 s. o8 z7 _" Y; b
write(const unsigned char *buf,int num);/ x/ T# e' k3 e, M( M2 a1 g
( A3 d% ?& Y7 \& g; m* T0 [( J
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。
! H0 S% Y% \0 v7 c8 w
% [* {( I: A% W 例:
- \' w9 x7 r0 y* n0 Y5 |7 b
" \- u0 J: r9 V unsigned char str1[]="I Love You";
) I" W; S. U. m# P
! ^1 P" [1 b* K0 n% I int n[5];
. S3 w, ]6 w2 u3 k7 T& n5 t
; n2 y5 M$ B* @5 v. }3 Z; t ifstream in("xxx.xxx");
* l' u1 k& {/ [7 l% q9 W4 ~! |& ^2 _ 3 m+ [7 S* l. ?8 U( K* Z! k. q
ofstream out("yyy.yyy");# F, u5 S$ V$ u
: G/ W! ?) x* R D" J
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中/ L/ }* W5 R, b- B
4 v' p& \4 V6 g4 W% N in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换: F6 `6 m6 O8 i! g! J
?. A9 f( Y: d8 P* P0 D" o ^3 n in.close();out.close(); 四、检测EOF+ f4 k& x) U) T" v- v& W$ p
6 G; K$ A: N& f' x# C9 ]4 f$ c 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();4 |7 g, W( L* N; s5 @
0 f/ B: J# l/ E. _5 e+ E
例: if(in.eof()) ShowMessage("已经到达文件尾!");
0 M9 \0 `$ i Y; Y 6 X* E: }2 k; {, Q: p
五、文件定位
3 B+ I# `6 g3 X$ g/ F 2 d5 |, p9 B+ u# e' | X
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
* d! w) H( y) f
" u. b! ]# N$ \) }( y6 i istream &seekg(streamoff offset,seek_dir origin); y3 R: h G$ a
3 s, D' l4 g; O( V' p- D
ostream &seekp(streamoff offset,seek_dir origin);+ y! ^' M" \7 q
z6 ~$ D- V6 a% z streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:: B S7 i# }8 n! U& \% W
' j% M# A/ Q7 ~0 n' C ios::beg: 文件开头* w8 ^5 z& v) }4 q# l8 m
1 c+ o: S2 f# A% _1 S9 t! ~
ios::cur: 文件当前位置
9 _4 ^* X8 s$ P- S' Q$ H
+ C4 D! V6 I) k8 K5 r; G ios::end: 文件结尾. f4 O5 _0 Y6 x- C/ I6 }. \# ^
0 X4 [9 A+ f) B3 u 这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:
* g/ s# [, d `% Q, V) c- Y 6 H( N5 F, z: Q/ I: d2 L3 y
file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节1 ^% | j$ e5 f E
! w) f F0 u: g' ~- |
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
& ?+ n4 N5 E* D+ }* n8 C( V1 G
9 N& P- t/ ^5 u1 g) w* A) G% l |
|