|
|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;
0 _ W' l* B5 Z/ n8 y6 T3 e' R9 h
* g' [* u2 ?5 i6 _ 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:6 a" ~# M J& E o! X
9 F! [1 Z# K6 B" T% P8 ~# x
1、插入器(<<)
1 p: S: a8 t1 g: {
+ Y% K) e$ m$ S& K$ E4 w+ }2 \5 F 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。! E/ A! k* G9 S3 N8 \# v/ ^3 A7 k
7 \% y2 |4 ?% m
2、析取器(>>)5 W! @9 l6 }* A) k
3 S4 u; z3 h/ Q/ [6 u& r
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。
5 @4 b3 v6 X5 o4 ]7 o9 q4 J7 z 8 o7 J* Y1 I$ \
在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。
$ o- F! k5 h- H- @0 E% Z a
\ \+ K) `* n 一、打开文件( ]7 @( R; ^% P( e4 \. m8 ~" h
- K+ ^2 S d7 {6 H5 K0 c4 D
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:" s: a7 v. n$ [& ?3 o* n
( [+ U1 G9 d* S/ h void open(const char* filename,int mode,int access);参数:; f; U+ t! K3 g# j
2 X( l* L& [8 m- L" t/ P2 C
filename: 要打开的文件名( h- l' L! o) H
7 ^- B4 Y6 R- b; H8 x
mode: 要打开文件的方式2 ]! L% z$ ~: J6 u8 s, K6 J
/ g+ A8 [, J6 X+ c6 O6 k access: 打开文件的属性
1 D2 l* \4 i8 A' Y 7 E9 b; N7 K0 z, n2 Y. t: ^' u' ?
打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:( v' E9 o: J- Y' f
6 I. _; h) A$ D% [$ C! z' i
ios::app: 以追加的方式打开文件4 z2 G) `& B0 J. q' Y6 O2 r/ B8 V
0 N. x$ i* h0 V( p
ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性3 z- i) }' V6 x; E$ [% O
& P, Q* e3 Y. i8 P: F
ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文1 k/ I4 {' ^9 e f0 o3 i
! I& |& P' _3 B ios::in: 文件以输入方式打开(文件数据输入到内存)
: {& R, g3 w. ?4 [# Y) Q! b
" J7 k& k+ l" s- ]; r3 y ios::out: 文件以输出方式打开(内存数据输出到文件)
0 f! s% X9 x9 ]* T2 J: ^% q3 e & h1 [) ^4 W9 _6 ^
ios::nocreate: 不建立文件,所以文件不存在时打开失败
4 L S4 s* h1 G5 R4 X$ w( d/ x
" {/ `$ w, S) B6 N+ p ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
: q5 F; n4 b, K. p8 N; y) L; u
* f2 o* e4 B5 m9 _5 } ios::trunc: 如果文件存在,把文件长度设为0
0 H5 Q, k$ q) U 0 P5 ~; ^( B, B9 l. h8 `
可以用“或”把以上属性连接起来,如ios::out|ios::binary
. T7 `4 @, A5 o* h4 e9 r( n( h
0 Q- Q9 l) Y# e: @/ i* B. N0 \ 打开文件的属性取值是:* p7 C7 j2 k% d" ^
2 q9 B& y1 \4 i# P, J
0:普通文件,打开访问
: }+ A/ T; g! [% @2 A & F' ? t3 Z" }' o* X
1:只读文件
: H$ _4 s$ T6 J
4 x) p* x; a7 r1 L( j6 l 2:隐含文件
' ]4 G, M4 ?6 j" S% X: o2 S5 q9 k- x
. I/ V4 M5 Y* H" d& K2 F 4:系统文件
( {7 X& @5 ^% {" H 4 T! y* T ~! T9 B$ o, t' Y
可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。
3 A+ w" i. H: `8 R. F' u
4 [- H: B) w, H3 a+ [% _, r 例如:以二进制输入方式打开文件c:\config.sys9 e' X/ t& G9 f6 d" D8 ?
' @; Y$ l: i$ A) A+ _, L
fstream file1;
$ a; I: k/ }/ ?8 o) V7 U t! ]
' v J* E/ g! {# ]7 V file1.open("c:\\config.sys",ios::binary|ios::in,0); @" |2 Q0 O1 x; p2 p i0 ]: v) g
' s' p7 O% K5 J$ W0 H6 e
如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
5 t* ]4 @2 f8 |/ l/ b
' d1 a, p/ E1 O3 D/ K/ i N( K file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);
$ Q5 Y# r! x5 U$ x
) \* W2 s" ]+ Y+ }3 U0 a, B 另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:5 W2 Y& V/ R5 j/ _- G2 `
" Y" R) L9 L' m( [ o: Z. m
fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
L# [/ z- T) T; R1 c3 L- h ! H( U6 Q1 T: M3 o
ifstream file2("c:\\pdos.def");//以输入方式打开文件
/ \7 j1 W$ c0 _% \/ B ! {( A; Q" C' n
ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
$ g4 f5 m" i5 u0 U4 ]; [. M
" A6 C- L6 }7 N 二、关闭文件8 u; Z3 l1 [$ H7 B7 u/ @
6 l( p6 B' E" L7 ~4 j& e
打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。* [% E: |, }$ l; B# p8 u1 I
, a3 H- \* a3 [
三、读写文件2 ]9 s# k! h/ d1 w4 _6 T
6 }/ w$ b' }% m, c3 _% o 读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
" @2 V2 M% E2 M1 N2 }4 U
+ x2 L$ n, I/ _( I& Q3 D% O q 1、文本文件的读写
7 n' A# h; ^# x5 ^( y( l
+ q% N1 |& x# A' i 文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:& |8 G+ N& M$ I; N
9 ]: C+ }4 o3 U1 R2 Y# ` file2<<"I Love You";//向文件写入字符串"I Love You"
# p6 z, F5 X( M7 F4 N( i+ { 5 U5 Y8 }1 z, M9 P
int i;' D4 d8 P. v% }' V& v/ b( A( L" X
8 A( { W! O8 q% c3 i* k6 u
file1>>i;//从文件输入一个整数值。
* h( [; e( R- E& v$ I
' s# O! ~: f. ?1 _& ]: l 这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些- V$ L2 X( W0 E% ?
* H0 Q) `1 l& v& u6 u; I' a# K1 ]% h$ p
操纵符 功能 输入/输出
2 i! E& W- F& Q Z7 D/ X. H7 I) X ( Y; ?. R, L) X" X5 c( Z/ w k
dec 格式化为十进制数值数据 输入和输出
1 p' p2 N9 l+ l' r- H( P $ [8 @2 C+ Z* q% |
endl 输出一个换行符并刷新此流 输出
3 J. |6 h7 g0 c- U' d
: [2 Z) |* r3 m8 [3 f5 m' _ ends 输出一个空字符 输出
, m+ }1 ^4 I4 e/ ~9 S2 Y' @) s 9 e! \9 N; N3 s0 a1 n9 `
hex 格式化为十六进制数值数据 输入和输出
, b5 d' X, l/ K x- p" V
7 I/ z8 v( `+ f, P# X3 F oct 格式化为八进制数值数据 输入和输出/ C6 o/ c3 \# f) L
' e/ x+ w3 a2 Q% Q: M4 w. K: e setpxecision(int p) 设置浮点数的精度位数 输出, y6 U5 ]4 Q. ~, T# C
+ b8 j5 O$ R* c: S6 `. l+ ]$ m 比如要把123当作十六进制输出:file1<
) X- [9 s( P$ ]/ u4 _- j 2、二进制文件的读写) M( G. G" \" ?& q; a' ]1 x
( u; Z: Q2 ~' J+ o- ~ ①put()
# H$ X7 P) B% S5 [; c9 [ , W( R' I6 v2 Y& `- t
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
) a3 I$ d G, U' A
: l6 l# D4 l" \% Z& [+ _8 I ②get()% D8 x+ P' k5 \8 h* n
" B+ `) B p& N i$ ~
get()函数比较灵活,有3种常用的重载形式:
" ?5 X, w$ ]- F( x8 Z y7 { ; h6 s$ u8 F z- B1 B8 `
一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。4 ?* a: P) a6 I( W$ _
9 {+ |9 T8 K9 _! B- r 另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。9 i' ?+ z% T3 y" H9 ]5 z
0 O" y9 h. }; Y: _2 \ j 还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:
/ s% S! ?3 A- I2 y5 e
5 ]# ^* @7 S' J. O d# A- q: c: \9 l file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。4 v- S- }2 m: r& C' z1 H& ~/ W# O4 s+ L. ^3 R
8 |6 W% a4 w3 u1 k
③读写数据块& u, i: `7 v& \; N. o
8 J8 R" z* x: d% o6 X 要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:
9 P. v9 r* T' B( U
1 x3 A, @9 [% y9 ]2 c read(unsigned char *buf,int num);4 f1 j5 G" r# x: z
5 {! s" H) t1 g/ E8 L) U; Z. @
write(const unsigned char *buf,int num);. _+ B! z3 c# C8 }9 r6 |7 {( B
" U; I/ I z/ B& _4 L# m7 p r
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。$ O$ Y" K \0 K5 l+ Q/ h! B! N- W$ x
2 l5 r+ E/ Z6 p% S: C 例:* i# d7 P* b3 y* M, v" q
) Q4 w, ?8 v* z' }* M unsigned char str1[]="I Love You";* i! t/ [+ ?& G; p9 Q: j
, k8 Z! P: i$ {' } int n[5];9 M' F" s {) }5 H
2 K, k& J! S, d) e7 l5 b ifstream in("xxx.xxx");2 a4 s) v& b7 @% N5 c( [+ ]& U
8 u6 s1 u& h5 `& b; U
ofstream out("yyy.yyy");
: _8 i8 \2 D" q 3 V& Y5 F5 `- b
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中, O T& v# k' f9 L9 a
" e7 I5 _' \$ N0 B8 |) G
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
( Z) Z+ _0 g# E+ d9 Z
0 F. {7 R6 F& z- j) G in.close();out.close(); 四、检测EOF A2 y9 P' c% z# x8 @# T6 b
+ n- x( G2 n) n2 I [& s+ E 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
( D' o/ G+ O! f9 Z4 u9 n
, Z- ~1 i1 V M/ W5 \ 例: if(in.eof()) ShowMessage("已经到达文件尾!");
" B& t% c0 x" n' @% b& F) ^7 t+ Y
" k8 @, n; [2 t6 H6 Y 五、文件定位
% v; |8 D) G3 g" Z% c. {5 W; g
* O. p! `- Y, x, t) w" \3 C 和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
) @" F+ b1 v! r( f' x& P
" S4 C/ I t- l& Z4 d: x& v istream &seekg(streamoff offset,seek_dir origin);
- x: y& N9 S; H% n; L; h2 M
7 T2 Y+ d5 k, N6 i: W- X6 } ostream &seekp(streamoff offset,seek_dir origin); A" Z t1 X, z6 K/ a( D! _
! S2 x3 c7 Y( y" ]$ ^/ ~
streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:, F6 z' K$ c$ t
; i' [+ }7 B$ l
ios::beg: 文件开头4 R* o" t) }5 A5 U# [( e
- W4 w* e6 j- g
ios::cur: 文件当前位置
' Q: L+ L9 J/ y, V& V* U8 n( P 7 q3 i& @7 Y2 w2 I6 f' O
ios::end: 文件结尾
$ N0 a% a2 R/ |7 A5 L) k+ r9 r5 z % B# s( @: p, S6 G
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:, C7 t" @$ }. z: G b8 z
% G% p7 v& X/ a file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节
3 z4 M s4 x( b) r% n 8 u, [0 g z s$ V) s0 @/ g' q
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
1 p7 F H3 X% q5 E8 }! \+ J- M3 N2 i0 W6 h- O2 w- V
|
|