|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;. t" ?$ X1 N, S* q5 Z/ Z
' D* n& H1 f. k 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:9 Y% O' T6 V! u: G3 e
! o0 |& G2 i8 G. s" ]; U
1、插入器(<<)
?& `" s+ f5 \ c O6 d) h+ }
# |$ e6 o2 u0 o5 S4 w+ Y/ d 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。5 T7 c8 O O& L ]1 i/ ?% Y- A
9 V7 S$ h' J8 w$ D- A/ V
2、析取器(>>) Y# S y$ O8 ]
7 i& l( { f' _8 H C
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。. i. k0 F6 u% }
- P4 M( }" g( h
在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。1 w; P4 c0 T( r t' t9 t
% W% }. f D, {% F0 ]$ |0 a" Z 一、打开文件, }9 ^ u/ i7 K* ? h1 z
V7 ^3 k$ y, R7 t8 h, r( n 在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:5 A. G- [( Y2 l
9 Q6 f/ Q& d5 {. Q) F6 H void open(const char* filename,int mode,int access);参数:
! ^7 s+ _+ ?- _ 7 ]8 m4 z: L! D2 G' W; |+ N+ i0 K
filename: 要打开的文件名
$ @# S2 u! P9 T. n- ~$ I$ V) @ $ b- c0 @- v% S: i7 Y
mode: 要打开文件的方式5 u: t; w) {& k/ L! T& `$ |7 [
, i! u ] t$ M0 o+ n# p8 P access: 打开文件的属性, y4 d7 W! y9 |* a6 X
2 Z, f3 O) w" c- v7 }: t0 z 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:4 A1 P2 [% w5 i& S( \% @3 y
. [# F3 D2 S- K$ ^
ios::app: 以追加的方式打开文件; B% D4 ^9 U9 r# m! U; }
. K# ~1 J1 R1 \* L" Z ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性
) l7 |( Q! \6 H4 y' z
8 n; u9 o d( o/ M5 h ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文4 h6 [ ], J! Q' t3 C o& e
z. ], X# P8 Z/ D# i5 d ios::in: 文件以输入方式打开(文件数据输入到内存)
- E; L; d. o, v6 K$ j0 L! Y3 z/ D N . Q' C7 {4 ~" @$ q+ [2 s0 O
ios::out: 文件以输出方式打开(内存数据输出到文件), `( D8 _( b- w
% f& l( r. t8 U, N( `1 x
ios::nocreate: 不建立文件,所以文件不存在时打开失败
, g3 V# W( _3 D1 f8 Y/ | + _* T3 e1 |' e2 l7 e, S
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
' e; i1 }+ y4 B/ s0 R: o 3 _ R6 ~, [# B. d
ios::trunc: 如果文件存在,把文件长度设为0
- H1 w2 s8 ^4 D& U K; h- ?% K0 b9 D 4 N: G/ O7 p9 W/ I# Z
可以用“或”把以上属性连接起来,如ios::out|ios::binary
8 t W3 Q# w$ H: d4 ]- ]; r ' @( h1 X {/ d3 a* A3 N; \
打开文件的属性取值是:
7 V7 \/ ^6 E& Y! L3 o/ _: ]5 D # e/ Q& ] \3 B( @/ l, M& C0 b
0:普通文件,打开访问5 `8 _5 V) ~' v4 u# Y
9 z+ K4 W: S7 I+ s4 w" L6 p+ k) R 1:只读文件
" o. u+ ?1 L1 d - h& u! O( }% B: ]# f4 }0 B
2:隐含文件
& L) Y& c8 m7 w' i 3 v9 L7 j( e$ M: C4 F- Z
4:系统文件$ ?# L1 \( f# u$ r3 @, r
9 @8 [2 Z5 H: c6 ?1 [0 b: o2 V 可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。7 G0 s& I4 w. }2 X g5 ^6 i8 H: d
$ f3 I5 u: c( d% n3 U 例如:以二进制输入方式打开文件c:\config.sys
1 E0 |# _! O/ e! M' K4 s
# o& C2 L" O! T* L9 z& R fstream file1;
' |6 j, W! F3 ]9 y0 e# o
1 f, q- | t* h5 |0 j% i# q- t file1.open("c:\\config.sys",ios::binary|ios::in,0);
6 O3 }6 N7 K! w+ I9 j0 o4 G! A ! c8 b; z! D. o* W- W m# j
如果open函数只有文件名一个参数,则是以读/写普通文件打开,即: |; s& h" ]" E" _
! h. @7 l9 X9 _1 p
file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);$ c: @7 ^1 R5 m; E
* Q4 j$ r+ q$ b 另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:1 o! v. J! h* x, L5 t5 Q% g2 R4 q& a
0 U! j, {8 Q+ { fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。0 {( k; m" {2 B0 i
3 L! e6 H) b9 i: q! v; } O ifstream file2("c:\\pdos.def");//以输入方式打开文件
$ w! n" q M8 z " |( }( e7 t4 H- Z$ q
ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。4 E9 \) S4 ~( L
/ j: ~4 T! c. E# t7 h9 j3 e 二、关闭文件& o( ? n0 S/ s6 z; V k
! p1 j& s8 v' M& \- [5 n( b8 i' n5 _
打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。7 `' p" P, d* p
, K9 E: }7 Y( a* j) i; B 三、读写文件
# M, x& S# {; W& v 9 B5 P8 K- x' r7 f
读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
( @2 b. V; c; X$ x6 M& L . ?7 n/ }( J4 i- b
1、文本文件的读写* \* g: y+ u0 p
w0 d6 H/ O/ r) w& J 文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:/ e% y- f- N# r: w0 Z5 V h
1 b' L4 b! O1 C3 r7 ^( f. [ file2<<"I Love You";//向文件写入字符串"I Love You"
" P* t. _: p& ]" @5 P
& o7 x4 \. l5 F2 r/ I' h' ? int i;
' }+ _6 R# |* s( e4 M
* a7 I8 l, Y# g9 C! N, m7 J file1>>i;//从文件输入一个整数值。* M9 h7 V6 L1 b, i& g9 ]) ^7 y
9 s9 R! U; Q& \
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
) j) N+ x. E' Z; R
: u% T0 |, F1 f5 e' H1 s' D( p3 o* | 操纵符 功能 输入/输出
- W- L- ]6 \; c& p m& g
) c0 a1 |- Q4 n- @ dec 格式化为十进制数值数据 输入和输出: d5 P- z2 Y( ?
8 E. Q4 T4 h+ M4 D. O1 a
endl 输出一个换行符并刷新此流 输出
8 b. \+ a8 G" ]# O- B0 _7 m - w$ O0 S& K; `
ends 输出一个空字符 输出
/ L( T- Z* K3 ]
/ ?3 g4 y8 ~- X/ N) |! {) l+ W hex 格式化为十六进制数值数据 输入和输出
9 M1 s8 W5 I) k0 J1 i0 W
) n( p( I. [7 G( p( K oct 格式化为八进制数值数据 输入和输出
7 K% T4 R) d8 j2 |/ l9 U4 r5 ^ ? 9 J8 n/ `& \8 X8 c0 j6 y; D
setpxecision(int p) 设置浮点数的精度位数 输出% r) Y% X6 {% f) B
1 L$ a4 L8 k Z9 w4 s# [& } 比如要把123当作十六进制输出:file1<1 P) y8 W8 l6 O0 C p6 a& I3 N
2、二进制文件的读写
$ i. ?' @: m4 a+ c. j! q& b 0 e1 ~( @5 I7 ~5 V, ?0 D
①put()
% O& a1 n2 `2 e; o 6 W4 J" o/ ^0 x% b' r5 ^7 F$ l" A
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。' X) d; A# D# ^7 A
" D* r0 C6 ^! d6 x
②get()
0 y- Y4 V$ |2 p2 Z: C . x; B7 c! `6 G; o8 u) `
get()函数比较灵活,有3种常用的重载形式:6 x. x' K, S/ g
0 f5 c0 j( c2 ]; Z* l* m0 h
一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。8 a, G2 E. X& Z% c5 Y' c9 l
w; t4 X* d1 ~1 A! m 另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。" W+ f/ I& P3 D4 o' o
, X7 N3 V7 C. |3 g4 P6 L2 {
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:
" c3 `; }" `. h2 ^. Z5 L " S% m3 _$ Q5 i5 h. Y: J4 G& F
file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。2 V F& x9 Z% Z$ a, K- I- Z7 G: i& i
& x4 x/ \; q& t& m$ [! j ③读写数据块+ N0 r7 l4 h7 k( |1 q% G) L) Z
9 `6 d, I/ X7 K 要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:/ r# s Q; H) B6 H
. {$ e' {# D% i, a' K' p1 ] read(unsigned char *buf,int num);
; _9 {/ W1 ~# d9 L6 {9 `/ ^ 7 p0 g* e1 f; o7 W
write(const unsigned char *buf,int num);/ M- K5 S1 ]* ~9 E+ u/ L1 j2 m4 G/ n
7 o5 Z0 T2 f: N. w2 z+ e
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。
3 i0 d O$ a9 j , \: Q! X0 {( o
例:
) h8 P5 q+ F) t+ X' R! s
( a5 F- T- O; K0 u) [ unsigned char str1[]="I Love You";0 {" ?; p. M0 K! ~
1 Z/ ~# e% L# Z! y int n[5];
5 v) b- C, z- j7 \' R6 }# B0 Q
9 e4 B0 T2 l( J m! G' M# r ifstream in("xxx.xxx");1 s9 A- h# ^2 ?
0 S) g$ V8 B9 e8 b6 m B! y( r; Y
ofstream out("yyy.yyy");& l! \9 T$ o \3 }- o
( g7 Z H% \& T% T out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中' f' Q2 C! m" M: j; c
5 y$ ^7 v7 J' z in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
& |9 h: J; y( ?! X( b2 ?
T0 }. p9 t) z1 ~5 c in.close();out.close(); 四、检测EOF' }4 o+ t/ d) n/ M6 g
. f z$ ~0 w/ Y
成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();" G w& M1 q" P+ ]' p
+ G) L$ q& {+ ^6 t; {8 w
例: if(in.eof()) ShowMessage("已经到达文件尾!");6 x/ O1 A0 K) N8 e! ^% X9 F& J
7 u ^' A+ F' b
五、文件定位
; v8 q4 [6 K9 i . A. }7 R+ [9 t5 ^7 E0 D: ~
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
) U, E7 D& r3 [$ [# ]( u& C! N
! M4 ~! v1 E4 F' B( |1 \/ g. B istream &seekg(streamoff offset,seek_dir origin);
; Z% D* G, ^3 w1 ^7 R' l : w% }- L" c5 _
ostream &seekp(streamoff offset,seek_dir origin);2 j: _. G {0 x9 G6 W8 u+ g$ w
' S' Q) k7 H" Y5 N% G! g! c# N streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
* A+ ~( K) y0 o: s' ? 4 f2 T1 r- L% r( G
ios::beg: 文件开头/ N- J9 G7 _2 w7 R, W3 }+ G, c! _7 C
5 E/ J9 i6 ]' t( n$ H9 B5 k' ]
ios::cur: 文件当前位置
* N! w# G; O% I7 Z& R, S% | * X3 I$ [" C! i
ios::end: 文件结尾5 C2 h+ f/ \; C, P
5 w8 p$ z8 m$ N- A- J! s
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:/ f# G& h6 {0 A% w
. c8 {+ _. g8 \ j( s
file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节
& ^1 ]7 t0 Z; G1 W" I7 j& X' r U
/ ~, j/ J- t6 Y7 `- n file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节0 u! I/ L. k+ {1 x& A0 }# y9 Z
/ b! u6 U8 w' }# S( r9 }- ^
|
|