|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
x
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;9 z. [; p+ K5 L8 ^3 R: `
: q/ k) C/ ?6 K( V5 ]. h
在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:3 S# @. d3 _+ l3 |# S
4 d" Q) J& }: J" `3 \, ~& _
1、插入器(<<)
' P( T$ G" Z0 k, A/ l. |& s% v
/ t" J- v) W6 u. Z/ d 向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。: P1 }7 |+ f5 k' L% s- }
# {0 G* B. Z% p+ S5 d 2、析取器(>>)
6 I" D+ y! b: }0 o: S ) _; @1 K: T1 N4 }; H8 k3 d; B8 e
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。
! ~3 w5 R3 G: L( [ ) X! Z1 `" L0 A3 N
在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。
4 A0 h0 J1 P3 H
5 m0 ~4 e; a7 f) w. v9 @ 一、打开文件; V+ ~! i, Y! U$ B! n; g
% K& x4 M C0 ~8 O 在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:2 t5 K9 U3 i3 P% R R* U
) T. F! p7 z( b( B! z3 G1 q) A void open(const char* filename,int mode,int access);参数:
. Q7 P8 f8 ^# V0 @( E/ J H
6 O7 x# p& v# C" X5 o7 y( S filename: 要打开的文件名
# G7 M0 l, Y4 U' s6 \
! a" k) t: P/ |" z0 Q# w) b mode: 要打开文件的方式
4 |4 P D0 S3 C. p. t. f- o
. L# t W! F! s( S1 H access: 打开文件的属性! D/ j5 l0 k; U; d
1 S ~ R# @- K+ B+ w
打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:# u0 m- R2 r" F! c3 ?
+ N. b: U/ s( G/ M9 z ios::app: 以追加的方式打开文件
8 G. q5 N w1 s. X) t
/ a, M; `* Q0 q4 @ C ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性, x( `: n+ r5 I# N0 `( i* C3 w D" \
8 Q' l' i6 _2 u; N" a7 x
ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文7 E& \1 O- B( X$ D1 [
2 ^( r" f& e7 o" J" E0 |' n
ios::in: 文件以输入方式打开(文件数据输入到内存)+ N/ U c$ B3 I$ m& Q
5 z' R W( o+ a% A3 }/ V# K: H
ios::out: 文件以输出方式打开(内存数据输出到文件)
0 d) ]! ~% C1 b
" T6 `6 Y* p, g7 N3 S8 P ios::nocreate: 不建立文件,所以文件不存在时打开失败! _6 Z% b8 p# b
! b6 U4 V# O/ q1 f- E, Y
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败# \% g/ z8 @. u* D/ S
& M/ ]! i1 P; x
ios::trunc: 如果文件存在,把文件长度设为0& ^) ?+ f. a8 g. s
; e/ V+ T0 a. v d$ }
可以用“或”把以上属性连接起来,如ios::out|ios::binary. `$ I/ v8 T0 ~; q$ s$ {
! k+ v4 }/ K7 }2 c) ^, Z5 V/ E
打开文件的属性取值是:
* z/ J* o; z- }9 @$ R1 u( a & w; v- c) Z6 j( v, |6 K
0:普通文件,打开访问$ r: v6 b; C8 B
7 P" J% y, q* ^1 q) C" V 1:只读文件
7 l& z( ~; W0 ]+ k+ V5 H' u0 |. d 2 c5 j: ]% {) _$ X s4 X; j0 x8 d$ k
2:隐含文件
+ u9 s# L) [; h, X
; `! p5 `. K% i 4:系统文件; f9 ]# j6 e7 j& u6 G; s+ T& d
9 x$ i# `: M& P3 u4 n2 G 可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。
: }; _; P1 H6 R. C1 |" P 5 L% y k; j2 A" T+ L8 n# K( B5 c! j' M
例如:以二进制输入方式打开文件c:\config.sys# F5 R& K) \' v1 y9 s
5 F a1 T: z" H fstream file1;* b! `5 d6 @1 X6 U1 p* M
7 N6 X4 \+ ~5 u9 ~
file1.open("c:\\config.sys",ios::binary|ios::in,0);
0 v. G# Y# f% @3 F+ x# ?9 Z 2 _# c( S. j. c
如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
' w& u; Q0 F, j
3 I/ n8 } `9 e2 n file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);
, E7 V/ o- d6 e) W. y! M
4 a6 ?' A' d; b; w 另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
8 u1 X. A/ l7 h, y; D) @( ~
8 z5 p' C0 m* A/ C, | fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
2 _& b: C, h1 ^$ |2 r! V
- ^) g3 `! ~' L* R ifstream file2("c:\\pdos.def");//以输入方式打开文件; M/ m( i8 N) }
' H/ o" h! a5 v0 P, x1 P! f W
ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。- h3 j) w$ F4 I
! O1 ?8 z; N c8 e9 S+ q4 O
二、关闭文件+ |& H, k3 [! w8 U) ]# I, ^' b
+ K7 {0 \8 H7 |8 E. R: R; I' U 打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。+ l4 }3 u9 B8 f" ~2 p, w3 Q
: X2 t& V( a+ T3 X3 {
三、读写文件
/ r# R- K& ^% s
9 ^2 f; M# t5 v, l& u 读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式6 v8 |' a2 `7 e# a
8 |7 q3 p5 z4 L c8 ~( W: ^
1、文本文件的读写
n' L* n% c. H9 V 6 Y: }7 f# u2 G5 z1 R! Y: o
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:! l) p7 n) N/ N3 v8 ]$ c) {
/ n( P+ `+ \' N L* J: V3 g. G8 w file2<<"I Love You";//向文件写入字符串"I Love You"% O* ^# y4 {: \0 G
, m: W- v4 n' B5 ~, } int i;
& O+ x( R, {: O6 `* d6 y% l
- S# M2 S" b/ `' A file1>>i;//从文件输入一个整数值。8 O( d% W K# l% v
" h8 e: Z$ d P: _% o 这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
5 Z3 c7 l8 }- c. {& [ S4 { 3 S' B0 V0 N: y' h7 y# I! E5 }. n3 g
操纵符 功能 输入/输出1 r8 V) x0 o4 E: Y8 \
3 n/ y* c% n$ t4 ~/ [) i
dec 格式化为十进制数值数据 输入和输出
$ D; i( E; @) e
* U8 F. B0 I9 G$ S# \& Y endl 输出一个换行符并刷新此流 输出/ Q3 o+ X$ P* m; s" O. k1 |
# D* I6 _! @) u1 H ends 输出一个空字符 输出
$ {& e( ~4 `3 [0 M" ?/ t P
8 W1 ?: b8 J. o7 O ~$ Q hex 格式化为十六进制数值数据 输入和输出6 Z2 j7 c" k) h
% x2 R4 u. J) [( d8 [* F1 f4 F
oct 格式化为八进制数值数据 输入和输出
j- H2 |" e) Z( U* |' s" I) ^
/ m7 ?1 w* l0 ^, S* ?# V7 E setpxecision(int p) 设置浮点数的精度位数 输出
) v0 F2 U8 ^) ` K5 Z% y/ u+ w) x- h
3 D( ^8 B6 }# N4 ] N 比如要把123当作十六进制输出:file1<
7 X. u& Z+ _! |& m+ V4 \ 2、二进制文件的读写
4 p; H" h% ?; Z. T! T " G* z7 f* K& q$ c" t4 {- O
①put() b/ K2 \$ p# `. k
3 T' q. S* N6 X, n6 N3 T8 v4 J
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
$ d4 g8 X) @6 [+ L6 d M4 V0 E
1 J& J( r' O1 q1 _$ p* ? ②get()# _. p# `( f1 \' H3 p2 x
2 s: B* B, ~- _
get()函数比较灵活,有3种常用的重载形式:
. i* U0 `. Q! l3 S, S1 s7 s
% ]: P' Q! c8 n5 [& ^# V 一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
0 Y, G6 V( r0 z) d
5 g+ ^7 k0 ]- q) C% t, l( m2 } 另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。6 b' {; }0 o0 s, S1 C& m
7 f9 }6 v6 X3 m* O, L& g2 \
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:
- _% A" A: b9 K8 Q( E ! Y/ \+ z6 L! Z- o
file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。
( Y2 p2 J3 D6 V% D# m5 s4 z
$ O" }. b) E) j W5 @( Y ③读写数据块; q1 ?- t' h1 @# C
6 Y' t% {+ [% g9 S% Z 要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:
9 ~. ]4 w3 a7 b3 t
% G1 w/ z4 ?' r+ a) V read(unsigned char *buf,int num);* x2 q# t% D+ j' P8 S4 c3 _
- S! t! S3 h$ O" O; [ write(const unsigned char *buf,int num);9 L1 {3 Y5 D6 c$ X+ _
* H Z( Z& z2 E0 {/ P) {& H* i
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。! W7 U N2 E9 Y! `
7 _+ ?6 a- ?" y7 ]* P 例:
; P8 C8 j7 }9 J/ X3 c9 g; W( R
4 j6 {0 X0 r) m- p3 O4 g7 X unsigned char str1[]="I Love You";" A4 g( `$ d" \6 z$ D0 K
$ k e3 n9 a1 H6 w8 n5 @! M5 Y* @
int n[5];
9 @3 z6 ?$ E' f" J+ ] * ]0 J; A; I7 ]1 ?% e( F
ifstream in("xxx.xxx");
7 z6 S$ M- i! e) H - |/ V; a; e% l8 ]$ N
ofstream out("yyy.yyy");
* e% j" a, ]' N! H" D* X8 q r a
' h* P/ \0 P: a4 U9 k. \) } out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
) W% [& }4 v) U3 }3 E+ ? " w, ^) Y9 t6 a$ ~
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
: m, x! { l" X/ k+ b/ H' ~6 R, f : J) ]1 \4 F# x8 R3 g8 Z
in.close();out.close(); 四、检测EOF
8 d) v- J: L9 \ G- |
1 ~1 J* i7 N" q6 ~! j3 b 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
* p) D j6 A( ?+ H8 B% q2 y
" f+ s0 y& o- H, w' z5 J0 M; s( i 例: if(in.eof()) ShowMessage("已经到达文件尾!");
9 U) ]- v' O& Q- E - t# ^; B2 f( x; j
五、文件定位+ g+ J+ X9 C% P! _: N/ R5 I' q
6 v$ _0 ]3 F( I( M( u
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:, U6 e G( e9 E5 Y$ j @2 O
. ?8 U1 c4 T7 D: Z; _. h* t9 F! D istream &seekg(streamoff offset,seek_dir origin); @; N6 z# E# N6 x
4 d% O* k8 m+ M1 L6 y1 i/ R4 }
ostream &seekp(streamoff offset,seek_dir origin);
- c6 L5 [% g1 d' J& K
0 O/ s, }5 a) D; k streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
' K. X5 _9 q3 }+ R' C( @
9 _: [# l9 {- `/ n+ O3 B ios::beg: 文件开头
4 V: d1 F* p' F 0 D5 k3 N: ]6 ]9 C% g8 z A, ^' W9 S
ios::cur: 文件当前位置
1 L" j/ G# U; e , l+ o0 ^9 V* Y
ios::end: 文件结尾) |/ u1 Z& L4 T
% m( b' `, u& t3 K* E# E 这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:1 L; I4 [. v: a
0 Y8 S% t# @3 N, O& m9 }: Q( x# k( c7 M
file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节2 ~) M4 F8 R! A" V( h
3 u4 @( O% v" V- e" B# O
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
) K$ s% |4 }# p Y' Z
% U/ J7 u# J- f |
|