|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;
5 l2 S ^1 b* O8 j* w
" x4 X+ v1 K3 w6 L1 c- n- t9 n 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:% q1 \3 S6 r# d C* S! F
0 [& a% D, ^+ c1 \+ G
1、插入器(<<)
2 g; }" v9 K6 j# ^, I 9 S, |+ F% T' Q ]" c5 W' G
向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。
, H q k5 p7 k! I, \ ( O! B+ t* v( L0 r5 _# ^
2、析取器(>>)
, V1 x2 {1 Z! a / `; I' n. H+ O2 q, N
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。
v! a& H% X% u9 j4 B
8 U7 o6 R$ P7 m7 ~4 I0 z 在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。+ v/ {* v h5 Z8 Y# m# n
# v6 V/ h' ^9 D! C: s% [' j* W 一、打开文件
" G d7 h& H, X! i6 C5 _5 o1 [
7 _$ w' D+ p+ X' V4 W3 F2 P& E. b 在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:# q* N4 h' @( S9 g8 M3 e
2 q2 C7 v# c; G% f0 }; ]6 o4 c/ r
void open(const char* filename,int mode,int access);参数:
! h' h4 a" x. T
* K% m# i$ f- W" }( D; V filename: 要打开的文件名
1 V( ?5 U, r2 ^0 \. l
) r: {/ y3 B) |" ? mode: 要打开文件的方式2 [) W' c) Q/ y R
- {1 X: x7 o8 P7 i5 K/ E8 x
access: 打开文件的属性0 _1 z* t$ u" F9 N+ g! F+ D
$ b. N4 \3 b! c' y4 Y 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:7 T' }; |+ g: _" A! h6 j
5 w. z* _7 X2 C8 s7 v8 v! ^
ios::app: 以追加的方式打开文件0 r9 }; \! f- g0 K* r* U9 K" _
& F' B+ G m: n! O, T/ W* u ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性" |* Z, ~* C8 T. @& }' ~
9 r. S4 _6 {7 q' k5 L/ p ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文3 Q8 o7 ~2 g* i! ]" ?0 ~
5 w6 P( b, j$ I3 Z: y8 @
ios::in: 文件以输入方式打开(文件数据输入到内存)& B3 e; v8 C! w. O7 R" R# O5 v* {6 r6 m
8 { J: @- A: C4 {( S
ios::out: 文件以输出方式打开(内存数据输出到文件)9 A6 k- f# t5 g, @0 K5 h
/ N& B6 k' E1 M& z. g0 k& e( n
ios::nocreate: 不建立文件,所以文件不存在时打开失败
@4 P% J! m% a0 a/ o, P" T - ?5 U# Q) F( g8 \, H& J/ j
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
: X8 q0 O, j2 r5 b' A
+ Y- y7 A3 W: {$ K ios::trunc: 如果文件存在,把文件长度设为0# k4 s0 ^" j- S6 q0 E6 t2 @5 o
; \' a ~* q7 a
可以用“或”把以上属性连接起来,如ios::out|ios::binary
5 x, Y" J( e' _5 o) u& b " n3 t+ G- ?; p1 x5 [
打开文件的属性取值是:7 \1 M5 x! {. m0 h; x
5 F0 d& K r- L8 _* M 0:普通文件,打开访问
$ ^3 e3 J K/ @! w, n
4 T# T" p* x7 ` 1:只读文件 [, G+ J! N) [
* v c: h$ l/ {5 \7 D' a
2:隐含文件
* s) X. X) N- h p8 ]
/ n& B6 A( i2 {- n$ D# L/ y 4:系统文件% O" S: l4 q' {9 O7 h- }* ^
* ]$ r6 V2 y6 ~5 L 可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。$ B$ C6 \$ u: K4 X- y& q: y' J
7 W( E! ]9 H+ g$ L" t8 ~ R, \
例如:以二进制输入方式打开文件c:\config.sys
$ l1 Q8 h7 [! N* [# V2 c) B' n6 L% O
8 M0 _/ ?; S) g4 b) E: G fstream file1;
/ z4 a4 C1 S, K/ z, V1 ]8 |
# e$ r4 F% K3 m( t, ? file1.open("c:\\config.sys",ios::binary|ios::in,0);# C: x; f9 l& ?# y' @- c
. e% t& r. n1 J; |' P. \4 v 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
& Z7 W7 V. T7 N3 ] \
: p' {4 i9 U; T5 g; ~% m$ k file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);. d. E1 ?0 ^6 z' x
3 a' u9 b+ e* F7 R5 Y9 c
另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
% _+ y/ S7 r% k
& D% A0 O1 e# }8 L- G fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
4 D% U( a1 D2 i
* n) _3 r4 |+ O- ~1 H ifstream file2("c:\\pdos.def");//以输入方式打开文件. T. R6 C; X6 A; ?% D9 J8 ]- T
* n9 a( ]% i8 `2 K; s+ F2 V" C M9 Z
ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
; s5 @; E# B: g9 `% @) b4 R % q" E' a5 u' Q. r- L
二、关闭文件
$ T; x. Q8 \7 S) v: m
% j5 F; u; `: n: E( {" g7 S 打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。
5 B3 g- p7 H" d4 A; N3 ~$ N+ h, v0 Q
L8 j( s- O/ V& d7 } 三、读写文件
3 T0 b1 b; g) o& ^ : T# y; h% ]0 y7 G- S
读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
1 X; d8 a% k7 D9 M0 _7 M' C& [: k5 V3 S W& m' G9 S8 f" n# x' M
1、文本文件的读写
7 M6 I2 F% E) W* U" O/ A& H
: {4 n5 G: d. D) b: W: T2 ` 文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:$ O+ t/ `: v7 ]' i) F
" F0 ^4 U6 [& G, G2 p0 n
file2<<"I Love You";//向文件写入字符串"I Love You"
( j( l" o+ _* m, M; @% L# Z: {8 Y0 H ` 8 j' M8 F: @0 c' {
int i;
/ E7 n8 D. k$ {9 S) w; q 6 r+ t7 L/ r5 f
file1>>i;//从文件输入一个整数值。
* {6 Z$ m, n9 I, Y0 u7 A1 s g. e 7 l9 w% o% M6 B8 H o5 y+ @
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
2 G; Z4 X- B a6 }
9 k3 i* z0 f) H. x7 u 操纵符 功能 输入/输出
3 q1 b& f/ b( _/ v! B( X 5 W9 ]. x7 Z& L
dec 格式化为十进制数值数据 输入和输出( y6 Q0 l( J _
, e3 w# M4 l# n
endl 输出一个换行符并刷新此流 输出' g: r& z7 t) U# X0 ]/ ?$ i
: ]$ E& ]/ ^0 k2 l, V$ n
ends 输出一个空字符 输出5 G1 Y, T# W; {+ u
& s+ H( j W- ^/ Y, q! v) m
hex 格式化为十六进制数值数据 输入和输出
/ Y7 m7 |3 y C2 f/ l) C, e1 q 6 q: _$ T0 A1 \" I! |* U8 q
oct 格式化为八进制数值数据 输入和输出
: h1 Q" E8 w- X, u 2 i* P3 s1 C* e( {( |- ?
setpxecision(int p) 设置浮点数的精度位数 输出
5 P5 y7 F; p& X( x
" U( e$ T d% x1 C. L4 J 比如要把123当作十六进制输出:file1<4 A+ R B- Z: f7 h3 P" K
2、二进制文件的读写7 \8 ] x( C' X6 q6 M
: i: X4 H0 I7 U3 Q. W' A% n( t
①put()& t: a* H$ J7 p$ h; A, V3 s8 U7 N+ b
" `2 M% |9 O' ]% ^' K put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。3 A ~4 O" {. R) J: X9 ^) i
+ U! k* ]! j' z4 ? ②get()+ {( x1 g& W$ Q# O9 e1 M) p# z
) f u' ]& q' J% ~ get()函数比较灵活,有3种常用的重载形式:; E/ C6 w. r5 B# Y, P% j
3 L) C# M' @/ N1 \! |1 x1 n 一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
b0 S+ Q. o5 a; t
# O5 B3 G0 m( P3 V$ x& b 另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
1 z1 s$ K$ |" I 7 n: O8 @0 I0 t0 M' b6 |6 Z4 |
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如: a7 | v. F& D
' t. R) M# G% G8 F, V* u; F) O
file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。
6 P! t: G! o& u4 @& [! W
" M. a& z7 {1 O- \0 T/ D& j+ m6 @ ③读写数据块5 O' G2 _8 C" ]5 b" b& P& P
( N% [6 }. }* R- K% T! V9 u
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:
2 H( e5 k; P( ]8 }& }4 G' [8 ^4 \ ; o) H6 s& ~ p5 y- m8 f, O
read(unsigned char *buf,int num);
6 ~0 L6 D$ j& k; O) U! w3 o9 W: B
( w3 r! @% e) l/ X6 n7 H( h write(const unsigned char *buf,int num);* v: e9 v( I. H
: T' [: e& U2 z# y4 g! N9 n, Q, S read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。
2 a: [9 e1 y* s* f
( u1 o$ R) F7 D: d q9 x% C- J4 [# n 例:
# g& e- i% m) B) m$ {* X- b + s8 A( i6 ] [
unsigned char str1[]="I Love You";7 P% |8 d) O: D' i5 p8 Y, o
^, F+ f! z5 j9 Q2 p; }' H. r int n[5];3 m2 } A& g. M7 ^# L
) p5 O" G9 v' V) ?$ P ifstream in("xxx.xxx");! G+ N4 Y8 p5 \6 g/ i3 m
. g+ v5 V8 Y/ M/ n1 @) Z2 r; W ofstream out("yyy.yyy");
; C3 W7 _6 I8 n% S. V# Q" z
; ?4 A. g1 r. A" j7 X; q out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
% z9 a. L- _9 J! `! C6 T$ F $ X9 N9 t% u2 r5 c( l/ D+ M/ @% f
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换& d+ y+ c9 L) v
3 _. Y, k. l2 k. H' q
in.close();out.close(); 四、检测EOF
( k- z' U7 p A# t
3 O4 X- B% M* c% f 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();, }/ D+ b8 I5 i( b
2 c1 Z8 o; R) l! J" R 例: if(in.eof()) ShowMessage("已经到达文件尾!");" z# _/ ~+ V! \) ?. n" [0 {
7 F* U) \5 H! }( C+ ~
五、文件定位; j1 d8 v& h3 P
+ h) i% ?- `8 y3 j# k, M 和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
4 u! n7 G& Z/ m/ ]8 T4 N3 g
, R2 }" [+ Z! A4 X i. G istream &seekg(streamoff offset,seek_dir origin);* u3 Y- U7 ~! O( [- L
5 G: F' h. d# u/ L
ostream &seekp(streamoff offset,seek_dir origin);: A6 C3 b. c7 [+ J
* r: d( m( Q8 e1 g streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:* e. x: ~6 d: w* a
# I* ]& C$ m2 w6 u6 H
ios::beg: 文件开头
* c% R1 h m T/ N / C; `$ J6 T( {5 i0 K) c
ios::cur: 文件当前位置
7 _. M% A" Q% @' m$ u: @
8 q/ H: S2 u% ~/ t/ p ios::end: 文件结尾% t) J2 u; e6 k' D; ~. f: w
+ ?+ C; ~! U: s6 R! ~ Q* v
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:% g5 k `& {% i8 t$ v! L
5 q7 |( G2 d5 t0 U! {7 ~6 b) F
file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节
1 I" X3 h# D3 A, N+ ?" p
7 ~5 L2 }( b [ file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
( P, _2 L6 x' |! E; Z( i) q5 O$ N* T* Q$ p- e0 t5 K, |
|
|