|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;' c4 @7 h T, j5 S' ~& v8 p" t/ ]
! l: ^( v4 ? B0 z 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:
5 R( t0 g6 X' _7 q, } + c+ Z6 u. \) p2 y2 ?. U
1、插入器(<<). ]) B& s1 [$ R8 o$ i
# B) b9 c8 G- U7 p/ z" u 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。3 D! P5 \( O: K/ g& K6 ]5 n6 I
7 W+ x& D$ C/ e5 V8 } 2、析取器(>>)
, v' J! x1 L1 ?" D ' Y6 B: \+ I, o* {& ]
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。& M P. `: \8 J. d; n
; V1 _7 J S; \- {4 C1 u: v 在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。8 t) T; p) h# F3 J$ d! c0 x8 C
6 Q) @; s& c: G- c7 N3 h
一、打开文件
6 n( r% D% Z3 W$ h7 l, r a4 h) ^4 G* w$ w0 M5 Z. O
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:% A( Q# U5 d- n- @9 ~. S. e
/ E8 G- W1 D7 B1 h
void open(const char* filename,int mode,int access);参数:' Z3 e1 y' T4 ^& d
) l/ i4 K, f) e/ r; Y6 v4 L filename: 要打开的文件名2 w, e" O2 g0 n$ I) \- ~( D
e3 ]+ a; }5 C7 X7 @' G0 C, |% E mode: 要打开文件的方式
; n) z/ `, P' S9 K) H
1 i& g& t- }$ R3 d& S2 ]& z) x access: 打开文件的属性
: F: c; H/ r3 H: [. E- F4 B9 R# ]
5 t) o, B, D% ^ 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:. v4 H2 g: Q& z: U& y( K
' P/ M& O' S8 d ?* O: r) b
ios::app: 以追加的方式打开文件
: x* B4 d' p$ v: l( E: L/ t" n + i2 D, y% N3 S) w& R7 }3 L0 O2 `& o4 p
ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性
) d; n% z* O( W1 j7 v7 k6 n : G4 g* h/ v% u" _
ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文
; c6 \2 d! m+ k- i$ g: ~- X
. j0 J7 \, d# k( @9 ? ios::in: 文件以输入方式打开(文件数据输入到内存)
% M0 D0 d, p6 t% K+ K0 V3 Q 9 x9 v1 Q1 g- ~, E$ ?6 G: I k
ios::out: 文件以输出方式打开(内存数据输出到文件)3 n5 q' c9 w. c. h5 w& o
* Z' ]2 S- |, u# W+ e ios::nocreate: 不建立文件,所以文件不存在时打开失败% l" B1 a. V* z& b6 b
- u6 H5 x9 k' z ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
- \5 Z+ `0 K+ [' K# M' L4 D& I- F ) Y8 X5 B4 O* y: v6 @. ]
ios::trunc: 如果文件存在,把文件长度设为08 G$ Z4 q9 [3 \
& Y, y' @$ D) y9 i0 C
可以用“或”把以上属性连接起来,如ios::out|ios::binary" | Q# R9 L( w. h5 _
+ E Z! _+ [" v! D# F 打开文件的属性取值是:
! ]9 t S) v$ y8 l1 Z
* c1 @% [- O- J5 x) _6 N' c( A 0:普通文件,打开访问8 i$ q& B' q% H: A9 C2 x
' l& K8 z7 D, ]' P" Y
1:只读文件
' u- e; X5 V- i! I% A& D 1 `; H, q1 V2 V) L+ ?% C
2:隐含文件
- y D- e5 m$ W# {6 A# e4 x- t
" L% V6 } t8 _4 W 4:系统文件' g' N+ E9 Z/ n( v: a$ n# s& C1 s
7 l5 H Q5 J% g$ b- h, m 可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。
6 d' L" ]0 G* D& |$ i ) W* G! {1 s6 t: j! E; \' O4 q
例如:以二进制输入方式打开文件c:\config.sys
9 T" v# M+ g) |3 k7 O1 ^ + \% X- }. Z- y
fstream file1;
]! N T% J; W$ ^9 H o( f- y 7 Q* G8 n. ?8 I) f+ T6 P- V
file1.open("c:\\config.sys",ios::binary|ios::in,0);0 H8 Y5 N3 m+ }, a. j9 B2 f
' I/ w! Y8 f- Z$ T1 O 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
! I. H" v9 T) K
* Z1 J2 e: s0 d" P5 p4 ^* Q file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);8 K# L1 y# }; E1 U- t/ p/ ], I
# G7 H7 m( A6 H W' i- g# ^* M6 H 另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:% Z% [2 B t( e& I
/ Q* e$ N' ~$ l8 W8 c
fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
# ~8 G4 w1 V& `$ x% }0 t7 ~
+ {1 q# l! g/ Z- {5 f ifstream file2("c:\\pdos.def");//以输入方式打开文件
+ ]' Y7 y# o( v" d6 F
* O9 R; P! m* O3 g# J ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。! ^% v: P/ n4 r1 p1 M" j6 U
& P3 i9 B. _( q" Z5 H; ?; q! D& r
二、关闭文件
9 t. ~+ N. L: ~( H0 X, w
' J* r; I& N: Z 打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。2 q* h& w. |# H2 ]9 u9 u
9 ]1 X1 k5 {) ~ u4 j2 ~ 三、读写文件
$ m9 ?2 a \+ G# n$ p, F: r' c ) f. z6 ?- J: Q7 B9 E$ O
读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
# s$ b4 D0 s6 n3 s& W* q4 f 8 A6 k- P0 \7 X6 S0 ?* u
1、文本文件的读写- L8 m4 q9 H6 W' w6 ~% O& ]
/ T$ R& R a" H# O. } \5 A
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:$ N% L7 O9 U4 s. K8 L. d) e
( D- [3 N% g! e' h
file2<<"I Love You";//向文件写入字符串"I Love You"3 G/ H6 ~% ~$ i8 O
! I3 Z; g5 H9 }3 l
int i;. x% H6 n: \8 ~ P; ?
" ]9 Q" Q T9 j. M% {
file1>>i;//从文件输入一个整数值。, n+ r, [$ n2 }* F
# u) ~- [' |1 ~- x
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些( R* H% Y3 ^% @1 @ n e
3 t+ s& H( c. _8 o/ H
操纵符 功能 输入/输出
! V A+ d, V9 Z( X# b 6 l8 Y6 n2 q) h) Q0 H) q# I( _2 g! {4 v1 I
dec 格式化为十进制数值数据 输入和输出
% M* t2 x: H; Z# W
6 E$ R& `4 v9 D& j% [# ]) G _ endl 输出一个换行符并刷新此流 输出
3 a! }2 ~$ |# J: f" l : j2 m$ J, P/ U, V) o2 ?# @
ends 输出一个空字符 输出
2 D2 C4 N! p1 O5 k ) E5 V5 D+ Y: g; u$ ], H
hex 格式化为十六进制数值数据 输入和输出8 V7 H" x) A; ~# F/ M3 A' S
8 P; H/ f. Z% w
oct 格式化为八进制数值数据 输入和输出
8 T' F! a' J7 j, |& O # d9 B( T/ J. s) `0 A, H
setpxecision(int p) 设置浮点数的精度位数 输出/ a9 ^( ?0 [7 }; V$ d
2 @% s J# G, Z 比如要把123当作十六进制输出:file1<
Q9 g' ]7 J) j* I3 F8 a 2、二进制文件的读写
" c2 p3 o q( | F1 m2 }+ A+ \$ n3 Z
①put() f" J1 C8 u. I# k6 R! G# C
. C, k( P( \9 G
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
5 Z( B2 ]. _/ p" \, G
7 F2 } S! I5 n+ ]7 A) Q( x ②get() n& n( b. G* O" f6 O0 t
; C8 x! }* q4 y- F3 {, e3 n; `* N
get()函数比较灵活,有3种常用的重载形式:4 Z# T1 a+ N9 ^2 D$ r2 k
9 t; |0 L4 r, E3 |: y1 s 一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。. G4 ~9 C1 g( b! }* u8 k
" z1 D. w- x+ R" {; a
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。8 i5 ]& [7 p8 Y5 h- p
. ?) I# _- I# _% w5 Q4 Z: _ 还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:' f p- C! b R& t3 l
2 g5 b+ [) q' O+ M file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。0 r9 S" ^3 q0 i5 T7 k
* @4 q& b4 C/ p. z8 d/ J3 } ③读写数据块
, N* e+ @/ A: U% w" a
/ M$ D3 B' J5 ~% t9 T- V 要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下: i& S. J' c: b' c) L# W
! c/ v" k; X, P6 Z3 M: P/ Y( }
read(unsigned char *buf,int num);8 ~1 }& |% G5 y
3 f- {3 u0 u+ h( Z$ k6 r. H
write(const unsigned char *buf,int num);
3 K, ?1 B1 W, w1 H N 1 `% m2 @3 Q/ Q% o5 `! M. O# w' {
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。
3 g+ D* u/ B/ D
7 j* y5 o5 O' [+ K 例:0 l: P8 h# l" z# r# N, [9 ?
6 g- R [7 s9 r6 e; m unsigned char str1[]="I Love You";
2 p) G4 F" ^6 L+ @! m ( @ s2 g, o5 d( ]* l0 ~
int n[5];
% p0 t6 r! e; ~2 M! ]
6 ^1 d2 G* v0 f ifstream in("xxx.xxx");
7 l+ s6 Z0 N, O ^* G9 y+ v; d- ]" u
1 I4 Q5 b* l G# ]2 I0 Z. Y; D' W D" e8 n ofstream out("yyy.yyy");
# d1 R& @) N- g% G O 8 m( f' r! Q# B
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中) C- _* n: l5 u+ i( {9 t5 E
5 ^: H' c2 j: I in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
7 W x2 Z8 `) h8 g' q: h
4 o+ N1 F+ X+ ~$ `& S in.close();out.close(); 四、检测EOF) n; ~8 n$ ` k: J9 O
5 n6 i& @# m" x8 q3 x9 d
成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();! _ j( j% l U# W4 _! O
5 J- _7 x0 |2 L) h 例: if(in.eof()) ShowMessage("已经到达文件尾!");. N' b% v5 b: P4 m: p- J
4 J- b: s% u V& A; b 五、文件定位9 j% n* u& g) l1 @
8 Z) u* v/ e# y+ \8 D
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:9 ^& `9 f$ Z7 W$ c" R
6 c& A6 X7 X* S- Y a- F" w istream &seekg(streamoff offset,seek_dir origin);
% Q8 X& q5 w' B" T 6 _/ Z& [) Z5 s8 N, V1 `, W! ?
ostream &seekp(streamoff offset,seek_dir origin);7 P D+ G9 w, S: M$ i0 v
+ ?) e8 ^6 s, y, `1 v
streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
7 e' b) r7 O2 X. s# z) J: f
3 I0 F! O# O& T1 U7 f ios::beg: 文件开头, q/ v5 q# J d9 ?
+ k) K% |# _7 Q+ x1 g+ y1 S! c4 | ios::cur: 文件当前位置" h. T! C9 r9 v7 E# ?! s: n- v' `
) L$ _5 A2 l, X! b$ ] ios::end: 文件结尾5 _! g5 ^0 ]( Q& k+ {; S; @8 L$ u; C
# ]; M1 l5 P) U 这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:1 Q. L% @9 ]; H; j' `8 {# g1 g
+ k) m) x9 Y: e4 r2 h `% ?
file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节
. y. R- `/ d+ Y/ H 6 W' h' {, b( K4 m) L# Z" Q
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节0 N" S. @: Q E! n. M6 t
& A0 M+ ?; Z1 B7 y- I8 B2 e9 T
|
|