|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;# o# b0 \& d+ h [& }
5 t f7 t( @7 i- Q. B; ?0 G, l
在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:# j6 {. }, M& }% ?. E
6 n$ t1 d3 W: o" g! c- U 1、插入器(<<)4 o* P! h' z- q/ `. E
* n9 g" Z- z$ U6 b" Y/ ^
向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。
. L+ ~/ Y0 d: j% K3 R4 o " U" o% x; G4 p. m) ]# ~4 t
2、析取器(>>)
- c! P4 E ?6 Y+ q6 N: J
k4 M0 x4 u. G$ w8 d3 U) e1 q 从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。
! o6 e. h2 n1 B, ^2 z* Z
6 Y2 i4 @' F# t4 T9 V& l3 u 在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。6 {; S. H- f5 b$ Y, ]( x
* n& ?& G( A! y/ o$ Y8 k
一、打开文件
# t* w& o9 L' T/ F) e( A& S, z ) ~; R' @3 @( }0 k( W# ^
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:( Z: i% \6 G ]* O7 Q, n; t9 g
& _2 l1 E. Y4 z void open(const char* filename,int mode,int access);参数: [. v3 {* N' p
6 {1 N$ }5 Z& }8 k7 w& H
filename: 要打开的文件名
1 ]# y% p1 |+ c
# J' v, L5 D s( W/ W mode: 要打开文件的方式/ ]0 V* L M1 L
% B/ C. ?$ j( A1 i access: 打开文件的属性0 T t8 i) {. E8 l$ {" z
1 |9 b% M* ?! B/ c6 c2 m; H
打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:( a! Z b+ e c# b7 G1 h6 f; [
& d+ K7 _& x/ M# b) y* h; z1 {) a ios::app: 以追加的方式打开文件
9 E" {* {8 A& v/ ^& S* ^1 Y) \ 7 {8 m' D% i( ^: w$ W- X+ k
ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性
) |6 e! p% O3 @9 d" C, M
, W/ b& T% o# }; G M, K3 H0 B ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文
1 m: x& \$ U" f! q; P
; M( ]. Y7 A) X( K' V$ A t( A! L ios::in: 文件以输入方式打开(文件数据输入到内存); h9 T: ^3 K2 u# V4 s
! R9 H: A" O9 w. k ios::out: 文件以输出方式打开(内存数据输出到文件)
" `! {! b! j) L5 K
; g* L2 a6 y, P( {% e4 Y5 {3 g6 R ios::nocreate: 不建立文件,所以文件不存在时打开失败. _8 [1 ?1 r* m2 L9 \. @
3 s$ b7 J8 o! B( R3 p- e
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
7 r% S2 R/ K" b# z' C* t$ ~$ R : z' {3 a) J$ B1 p' I0 h1 {
ios::trunc: 如果文件存在,把文件长度设为0
. M* Y" m* y6 D2 h& o8 l
1 `0 A5 I3 n" A1 ?5 [3 d 可以用“或”把以上属性连接起来,如ios::out|ios::binary9 O! i) w7 N8 [0 q/ W1 E; O
' V5 L, B% a9 X. M' i3 r9 S8 z 打开文件的属性取值是:! b4 N e1 D2 G+ `) R
- ]0 W# V/ J8 F 0:普通文件,打开访问- D1 W1 n& d8 d+ N
/ F4 o N9 C" D0 p: a' X
1:只读文件# H9 z0 q/ i3 w% T; }8 [# ]
9 _ ~: L1 q% n8 I 2:隐含文件
, z7 X9 R( c5 D, P3 f1 \
' T$ P* B0 F F% v 4:系统文件
) t$ p7 k$ D( O# q: E8 s- Y8 P$ N 5 E x3 ]# o) m# Y7 R
可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。
6 K* S# g" K) u) ?6 M 2 B! X+ q! m# n0 |+ v- ~5 Z
例如:以二进制输入方式打开文件c:\config.sys9 @; i+ h- ^1 {
, {, _5 D+ }. ]( {: Q" N fstream file1;, P. @7 n- O9 N. X! V$ a# c
" k2 J/ ?0 y7 Z file1.open("c:\\config.sys",ios::binary|ios::in,0);
& [: y9 [! u. N& ?1 o
1 g' u5 R! f: E4 N) i* W# f 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:: R }3 c( b( h, h# e, y5 q
! F" }- x/ ]; L/ M# V! r+ g: R$ r file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);+ ]( s) o. V8 v" r! L
* e7 K; Y- u0 k8 S5 T! n' e$ G; M) X 另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
& a% Q+ a' M0 x& Q) n+ x7 N; s - f6 }! I+ u! Q& W% r1 Z
fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
+ i d9 D# J! Y* c* l- u1 {+ H 8 K) O- `8 N, Z5 O2 S& e, @
ifstream file2("c:\\pdos.def");//以输入方式打开文件( u8 t/ ~2 f+ A8 K0 }
9 K; D9 G k' {+ M" T M* O3 e+ y9 f9 H+ P
ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。% L/ ^/ I5 \, X4 ~+ P7 `3 y
- f2 t2 q8 f0 k( H$ D- U1 W 二、关闭文件
% }( N) m: ]8 ]! }3 t4 ~ ; s( F- N0 D" {% f+ Z1 B+ d- H
打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。. H5 Y) o7 f5 O
' c1 E. d! c5 m, M
三、读写文件! d1 [" D7 _0 N; I9 q# U9 g6 S
9 |( s. Q9 P. [+ u9 T
读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式* f; X5 l5 b% R0 [
' Q$ r( w" R' K8 e3 }& T" ? 1、文本文件的读写
5 B* g! E4 Q$ s+ S- y 8 h$ v4 r4 W V' T2 R6 g, L% G" W/ A
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:5 Q0 X2 U- p+ V5 r: Z, Q( u
. f! Z. V/ I7 s$ F
file2<<"I Love You";//向文件写入字符串"I Love You"9 J( E* Q5 a$ Y5 g
8 L7 B. q/ r0 H/ W* Q$ l int i;8 {( ]- N9 j* _. J
6 a- w+ X! z! G6 d6 Q4 Y# G2 I file1>>i;//从文件输入一个整数值。* v9 t1 p! I* p+ P
! N+ R' g' l% g; h& `/ I
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些& g% d5 o* i& @ D' {
6 u5 q/ W: d* M' C t
操纵符 功能 输入/输出
, n0 P# V# y' [3 I9 z
0 A' w+ Q4 _, ^; o dec 格式化为十进制数值数据 输入和输出
5 w: ]; R5 z- u6 E$ p3 E + A: @. P5 N/ \( s* j
endl 输出一个换行符并刷新此流 输出4 ^9 L0 d- A# l' _
: L. K. R1 J5 D' [% N6 M
ends 输出一个空字符 输出
4 `3 h& p2 a* n' S
# z' S5 a$ Z9 t }6 C hex 格式化为十六进制数值数据 输入和输出
1 ~9 V- S" t# M/ V: i; t+ Z; w; U
1 ~! g: M+ Y; F; I2 n oct 格式化为八进制数值数据 输入和输出
" K3 U" v* N- x9 a9 q* N
8 T" ?- P- \$ u7 ` setpxecision(int p) 设置浮点数的精度位数 输出' B% B9 w, o; |2 [0 n; [# |9 g
/ X+ n; ]$ N4 y; m' l# n* `" M- T
比如要把123当作十六进制输出:file1<
( E# k7 B# w a* b6 { d 2、二进制文件的读写
* q8 ~' \9 U+ v% U / c5 K0 K a% v5 t- A! ^
①put()1 r/ m7 j5 |+ }
1 }" @, l/ w, H% x! n2 x8 a! w8 ` put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
+ k; s! Y' d6 j/ ]# Z5 |$ L- Y3 {. U 9 s& g3 N( B- K' C6 W4 [
②get()& q8 N Y: _- |
/ ^2 W. `( Q; e1 M+ t; } g6 e; d3 Z get()函数比较灵活,有3种常用的重载形式:" R+ r; q& q8 h
j0 q |. }2 _ W* R2 i- q4 g: r; a
一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
( r7 R# j8 k' k2 U8 x# g& H 8 u" q/ h3 u) }( j, F0 O2 W
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。8 P4 L' a9 _3 h
8 Q% \8 R1 K q; ~7 ~
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:
* ~' I: t* E6 X# j
! b: T' l) r7 h. V% @2 A p [$ O file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。
; q% i& S% L: _! }3 A6 I2 l : T, T0 j. \& Y9 i6 Z
③读写数据块' R- }7 l' I7 a
3 p0 Z9 W" A/ V( D$ o0 j3 q 要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:
; H2 ~$ h/ [/ M/ `3 R, n & F) V) A: r5 \7 e' P7 @' Y
read(unsigned char *buf,int num);
- A5 `; v# H- S5 J
3 d7 U9 z1 q+ q& f/ w* N write(const unsigned char *buf,int num);5 s$ f ], l4 V
3 ?$ j8 u% R' @* F7 s1 U7 O+ |4 S4 ?8 J
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。 P3 m* m F* }# A/ P2 g
; R# ]; N: \% H3 `, B5 \& s
例:
4 g' _) ~! P. e' j 9 S+ f- s g6 U0 l2 @
unsigned char str1[]="I Love You";& x3 ^! x* ~- x$ _
6 v& B- d7 K6 d int n[5];8 k# K4 V) p- H
( A4 \; D( d, o% o ifstream in("xxx.xxx");
) o, n" ]1 O, u9 s/ W5 V2 r4 u
2 {3 [& s( Z% {9 }8 x ofstream out("yyy.yyy");
2 z/ V3 F) J7 \0 ^9 }/ r% P( A9 _; n , w$ g0 T2 O# S
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
) G$ w' Y7 f$ U4 u* Q) O
( C3 ~, X F' @8 ~: j in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
1 z, x& P* h5 Z3 g& h6 u$ j- s
5 J' Y1 J+ z y& L" I( | in.close();out.close(); 四、检测EOF9 n9 G4 U6 _8 O" ^! m8 B q4 j) F
- ~9 y( _4 p2 I
成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
+ M# L$ e" v- v6 J9 R# J C9 {
3 [$ X; r4 c4 d, m. [ 例: if(in.eof()) ShowMessage("已经到达文件尾!");
( B6 A& |- U: Q' c
0 d2 D/ \- }% @( `9 S( \7 z 五、文件定位- b" g7 b" r2 h) @5 t# {
) R' b# g$ q6 D. p! c 和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
; Y6 Q6 i$ U5 T( V9 t) P 9 t5 r7 G7 ~# n( s% t% p
istream &seekg(streamoff offset,seek_dir origin); ^6 R9 h# Z* ^7 c$ j; G! O* P
. Y2 X) H$ ?7 x, u( S
ostream &seekp(streamoff offset,seek_dir origin);
6 J% R; B+ M3 N- a5 o, X% m O
1 ]4 N a2 a, t7 S+ P! G: f streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:' Y9 m6 o8 L0 u) _3 }
) J2 @6 ? b6 @0 U2 t, [ ios::beg: 文件开头7 w+ E5 m5 C' n
! E: m c% b2 b% f
ios::cur: 文件当前位置
9 b; M0 m9 ~) A5 |
, y2 H r. v; s0 ], A ios::end: 文件结尾
2 O: g- j" c- J* o8 ? 6 X4 d5 r7 \/ Y/ ?7 V! L0 `* T; g
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:( ^) t+ s( Z E; o/ l
- S i6 D. L. Q. n file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节
0 N8 k. {1 K' I9 ]
( X! r0 L. b2 Z. w4 b S0 N file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
7 S5 {9 `; I4 i# s+ d0 M0 |" b6 _/ B5 c8 x: T
|
|