|
|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;* Y( o9 ~ o2 r g5 A' e, V) `
. l9 S* v( O7 J# O( E! L 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:
$ `( V% r0 |- c
' G' Z. j' N2 Z; u* E 1、插入器(<<). e# v% j: Y! y" W2 f2 S
$ L0 c$ D; `1 h, Z' |) V9 ?1 |( e 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。1 Z- f4 Q# f3 b Q" ]
' P6 ?% S0 Z2 O8 {5 ~
2、析取器(>>)7 @* u# x- J9 Q/ ]- l1 P
- q) O: j) y1 M: e8 s 从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。 ~3 u* ^8 N: D0 H+ T7 S
2 L' @6 V/ I0 b- \# C3 d5 u. _; f 在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。! _' _3 z' K5 m
0 B, M" w# z' I1 ^5 [& l! q( _! I& ~ 一、打开文件1 F$ \: y7 Y0 t4 b' F
7 t/ |7 F% M6 K1 h' G 在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:( P5 {" z4 t* A) g
" i0 c* W0 m9 G8 X& j3 y8 [ void open(const char* filename,int mode,int access);参数:% q% x& R' Y( [* D+ q& _; `/ c
0 p; q' {% m: d h filename: 要打开的文件名
4 Y C }( Q4 O/ L+ P1 _5 \ + |9 d0 Y* o3 K( p. s1 I7 \- Y
mode: 要打开文件的方式" l1 w y9 G9 ~9 _
6 W6 X6 O, J# x! R
access: 打开文件的属性: Z# `( t% z5 Q$ h+ q% [3 R
& F7 e1 ~' O. q# ?& [ 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:5 E# D: _; S( w4 y( H6 s! Z
: Q P: A3 l3 _% t, y ios::app: 以追加的方式打开文件
: f1 T0 l% W0 _( e) h) a# R
! j& m( R, q; ~1 ^) R8 f& S ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性
& ?# \6 m8 x7 P5 ^ ' u; M, G3 W* O
ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文
6 @3 L" l1 ~% b
, C+ c/ @6 \. @: \ ios::in: 文件以输入方式打开(文件数据输入到内存)
" |0 K/ I2 j& M0 I6 u' t1 r, [
) a$ `# a( j" I2 Q ios::out: 文件以输出方式打开(内存数据输出到文件)/ o$ O, A3 Z" G# i( ~0 W/ Q! T
, `8 j2 T- R/ g1 x) h ios::nocreate: 不建立文件,所以文件不存在时打开失败' l C% z: S' z9 H2 I( W
- _) l/ }' {2 M ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
! j: P9 p: {8 n6 D; C! I: D F # Q* Y6 F4 W; J
ios::trunc: 如果文件存在,把文件长度设为0
6 ~$ A+ i2 T/ d% m4 ^( I) l 2 \) q0 e( [% B3 n4 |3 j( L, q" ~
可以用“或”把以上属性连接起来,如ios::out|ios::binary7 v* e; e$ n* X# e6 V
9 h* f1 r/ y% t; P5 _* x8 X8 t 打开文件的属性取值是:0 R/ r* P- A6 q7 T# ?" ^5 `6 @
3 G9 E3 \) T1 {3 G1 \& E
0:普通文件,打开访问
) z% O/ @. \5 o P& i" i: `9 Q7 c ) ^2 k5 d/ i5 u$ ^: b# ?$ B4 F1 N
1:只读文件
% [$ Y7 Y9 s$ b0 w
& ^5 M1 d8 B; v- S& q 2:隐含文件0 C8 j, D1 w7 i8 W
, L j4 V+ s) B- a# m: j 4:系统文件
' R4 r+ N3 p |( R* b, ]( o - a* k/ ^- p9 S
可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。
4 [; e4 e' K/ C: O# ?$ i 3 v' R# J+ Y# ]7 X2 ^
例如:以二进制输入方式打开文件c:\config.sys
6 b1 ^; I) s' I$ X6 L 2 G$ E1 K+ `- B1 m' M
fstream file1;
4 K" }9 Q+ B3 R8 k; j+ G 1 ]6 f$ m% F! u1 A7 d7 |$ C3 ~
file1.open("c:\\config.sys",ios::binary|ios::in,0);
0 E8 K* w$ D: `1 r; L
+ N- j# |0 ~9 x/ y) n. w 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
+ G" u5 I2 p5 n0 Y. ?, X+ L
: P+ R$ B3 P( J- ]' G& z file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);/ y; r! p* L. O- z$ x
6 g$ Z% c+ Q" C2 b 另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
& U- Q0 Z+ L4 [9 q
: ?: _! i$ X0 Y fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。. K2 t" L/ o* H9 j; b3 o
6 y6 B5 N0 a* \5 x- c ifstream file2("c:\\pdos.def");//以输入方式打开文件
1 N5 f3 |" d( P
) c- h/ P# b! x/ f ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。1 u: l3 n X5 G3 W; G
) b3 b+ J; |" u3 q2 l0 s
二、关闭文件
. O) s. ]+ |; y( d 1 Z7 ?% i6 s0 _3 y. q+ A2 t
打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。/ I5 U/ y' S( J) Y- r3 `( j
2 [" n, i1 r& ?9 i 三、读写文件
* E. V4 {3 A4 f3 g
+ P6 Y: O' l; K5 m F) O2 w; K 读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
% D, Q. `# o5 W3 L " {, ]9 B% G4 m2 @4 g
1、文本文件的读写3 S5 f, Y# P& p W8 u# n
5 ~! c& K, Z8 c: b, T% Y4 w
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:
; o3 U5 s& L# t o7 ^ ( f9 O1 y4 Q1 {1 ?% ~) A+ |# Q
file2<<"I Love You";//向文件写入字符串"I Love You"
$ U1 n) V4 J* m. k( G % ?2 O; r# ]0 H& M2 `3 p- i
int i;
) O, |) v$ _6 s, D* h- o 1 T( t' n1 [) ^1 m
file1>>i;//从文件输入一个整数值。
2 I7 ~& d3 h4 h8 Q6 J; ^ % o: J$ M* j6 d F- X1 k
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
3 w# _3 ~, a8 b
2 r! M& p: t; q, ]7 o 操纵符 功能 输入/输出7 P6 ^9 ^9 M3 }: \: h
4 ^7 h, y/ |$ V. m: n/ d
dec 格式化为十进制数值数据 输入和输出
/ i* r$ o0 ?+ I: Z- J3 g $ c7 ~5 \, H$ L) p" Z! `) B% v( z8 L
endl 输出一个换行符并刷新此流 输出
: m3 _: ~. ]; b& C7 \* m
: l8 {) H' f! } ends 输出一个空字符 输出
9 Q. W. ?3 E- P6 `$ j & Q8 }) i F( q9 j# V) O
hex 格式化为十六进制数值数据 输入和输出4 V! K5 z* `" }* U/ p% D
) s( {2 j7 B; p- w# k# y$ G& y% n
oct 格式化为八进制数值数据 输入和输出! B. [0 W" ?: e, L7 E
5 G0 t* ]. j% [( h' f' x
setpxecision(int p) 设置浮点数的精度位数 输出
' W) S4 y& s0 U: _3 f# ? # u" L0 _5 C" v8 P5 M
比如要把123当作十六进制输出:file1<% e3 ^7 H: P$ E$ s/ j
2、二进制文件的读写
3 [+ C" D) L/ V4 U) J
5 A" I7 B+ T% ]0 d, t# Y G ①put()
& b6 u* x' V7 O. x& ]/ z, {/ e3 j F - z, Z% K, f4 X- |# M: }/ d/ n! B
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
/ Q! s& c# X* Z0 y% P9 b
' Q$ y/ y7 D' u% l0 Z ②get()$ Z6 j) X) F* o
, ?* @$ X2 s) Y4 p! d
get()函数比较灵活,有3种常用的重载形式:
T0 v" y% L* n6 @% y0 a; F$ C ; F& |4 ~1 J" A
一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
% Y/ Y* K! f9 {* w& C / V9 h0 F2 `; }
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
& b" T- {# }/ C; i- a
3 K F+ ]; N$ C: z* L& z/ U! k4 u 还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:4 Z2 ~+ J& \0 M$ c: w% E& I
8 @% ]5 @8 L- ^0 H
file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。1 q& L! a4 [; i4 q, u
4 q2 D+ M# Y4 ?% z# S1 k
③读写数据块 J$ `; `6 f: m d7 `
+ I7 k8 Q8 V3 r: @ Q
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:* E' ?5 {2 A7 n# S
( Z/ n/ Z9 P# }' l: e( U# z read(unsigned char *buf,int num);
3 F# E* q- U4 @/ l, `! P
: R' G* U+ f8 K4 ~6 G write(const unsigned char *buf,int num);
: `( ?2 w4 s# D. W6 s6 j* w3 P ? ) z% w6 |& e3 O& Z" k4 L' ~
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。: {: q* `- @; n, p$ Q
! h" X. Q! K0 V
例:' Y6 O# I" P. @2 }9 g* _9 Q
' u" s% M: K" _
unsigned char str1[]="I Love You";
" Y p1 \# i; A& b- ~: a, m. R& n # ]6 w' M R5 O% i k! [
int n[5];
6 G/ k* d& G4 U
9 y9 i$ |; V5 G, H- H/ ^; ^. | ifstream in("xxx.xxx");
9 t' }5 V& w" N6 Z3 ~8 w
: p1 o( q6 v U$ g7 j3 y& ]+ @8 ` ofstream out("yyy.yyy");
3 h# k! ]5 D1 j 5 a- H6 K9 H/ ~# D2 I, O' Y; v
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中0 |- J6 h5 m# U/ p j8 r9 e* m
% ?5 i& Q& k7 T in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换6 }$ T4 P5 o( v+ G3 r5 z
& L: }: D! D9 v6 e6 ?4 C y' B
in.close();out.close(); 四、检测EOF
0 e( n" G$ i5 [; n
- m5 D. ~$ L, b( M' O# U4 K 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();7 n6 C$ Z9 _8 ]3 j n$ ?
5 v$ s0 U! ?! Q w2 Z
例: if(in.eof()) ShowMessage("已经到达文件尾!");
7 L d; F8 H O5 ?; ?$ B
# D0 u4 O) V8 h7 w 五、文件定位' m* ~- A3 t6 B
4 m0 A/ B$ L; a; `, P# U 和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:: D# }% f( u# t( R8 v! S2 G
- [2 `: \3 Z, f3 K6 z
istream &seekg(streamoff offset,seek_dir origin);
+ B; l; F; f- c' `9 X9 f+ |
+ L% ?2 I4 w) ]4 d# S% r9 ~ ostream &seekp(streamoff offset,seek_dir origin);
& R N& g9 T! B, h ( K7 H; ^: V v3 e/ X7 J
streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
- I( O/ r% l2 B9 v ; R) @! @5 X+ c, i$ t
ios::beg: 文件开头
/ ^0 s) K' X. n+ Z9 k
! E' o$ C# m' X8 E5 Q. M ios::cur: 文件当前位置0 ^+ p x n, _1 K
5 I7 a, p) g9 B) ~) } ios::end: 文件结尾" W+ G# @. Y4 u
9 A3 {9 K' h9 ~/ q. M6 T
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:
% d3 E& n' e! |! G2 L
; Z, p7 {; R& }+ F file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节
" I! f, A3 V( ]7 G/ P) b5 a" S- V ( B! b, V. Y+ _* W9 [" N" T
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节8 S# I; u0 C# J1 q+ l6 M, B
' B, l; L! s- T" ]( p7 W9 ]
|
|