|
|
请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!
您需要 登录 才可以下载或查看,没有账号?注册
×
ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;) @" u4 v5 j' o( O# G2 E
# |6 L$ ^9 W9 b6 R# ?( b 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:
; ^; x; c3 p- m0 O0 Z0 E1 j% N/ Q / ]- H2 ?6 t, \8 x! Y' i
1、插入器(<<)
% `1 W) W# R/ p5 s% l3 K& J 2 C/ Q& ?% i& p+ b/ m
向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。$ Q y" [1 k9 ^+ n% g
4 W M% r/ _$ f, C4 y' c1 s5 I
2、析取器(>>); H( L( E4 s/ u Z: ]4 N$ ^
9 V4 a5 J: _: m" u 从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。6 ^0 ]6 d' C: A: I' `4 R
( C4 b8 q, \, F w+ [* g 在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。8 H* C* y3 \2 |1 i
+ F" O: R: N) Y4 r* ~ 一、打开文件
6 w" V1 R9 a! ^- j3 G1 K" j % K- G) r% W$ p7 i) E! f
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:
4 P* ~4 x) `( r3 r: S6 v8 @; \0 Z
0 k0 e6 X* s$ t+ `4 t void open(const char* filename,int mode,int access);参数:3 w6 v% E5 t* }" G' V
" x) _7 \& r. F5 l filename: 要打开的文件名
; j" L6 Y3 D" b% G% o) Q
( E7 X$ w( d6 w W, }/ a mode: 要打开文件的方式
, d3 P6 U% Y' }7 d" J $ [ l7 I0 W8 ]$ F, Q- {: u
access: 打开文件的属性
( Y. m* ?1 M, V, M6 X! i
0 a/ n+ [% b' e# u 打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:6 i( i6 p9 N4 ^0 _, a1 C4 L3 V
( f% `( c+ q2 M, m; ]$ J O: l ios::app: 以追加的方式打开文件. Q# P0 N# A& [7 F8 ?& s
8 B9 _7 c) s& r* o! k0 _2 b
ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性
. F6 V9 ?) L% `, Q- [, A- a
0 l" S! A# `4 S ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文+ \$ z, E+ B& x- R7 p, U1 c) G* v
5 y0 ]% o: j. s5 q: l7 S. d C ios::in: 文件以输入方式打开(文件数据输入到内存)7 v- Z" l# l% m& Y* y0 k* R2 V
& {9 z( w! X( n ios::out: 文件以输出方式打开(内存数据输出到文件)
: Y% \; C+ W. G$ U" W( D( i/ }& z% y ' }+ u: E7 a7 i0 g) V+ P0 v
ios::nocreate: 不建立文件,所以文件不存在时打开失败1 E! f- v; E8 w6 Y& _
5 B4 Y; d( |5 U8 i
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
3 a/ ^) d n0 s8 I$ X( h" [ ' \0 e# m8 q' T% B$ \+ L
ios::trunc: 如果文件存在,把文件长度设为0" F" Q1 G- s( O( V* X
7 I. z" I' ^; z$ w0 @' j
可以用“或”把以上属性连接起来,如ios::out|ios::binary
2 a! i( O- Y& S % W" W* V# R1 O$ U) b% o' F: n& P
打开文件的属性取值是:
: A' @( N& e! l8 K2 l/ N * L* @4 |. |* Q
0:普通文件,打开访问4 ^- z6 c+ `" B$ ^0 i5 r3 l0 I! k- z
$ x, v% X$ U: q
1:只读文件
' H1 e1 A' j. X2 |, K 9 k" A8 Q q" z5 Y, E$ }" A
2:隐含文件
' g4 H" L* X5 h! U7 k3 b! B) a
* C; d2 E, t6 H O- [1 ]0 Y 4:系统文件' c6 u9 ^3 t/ {! t
# ~( V+ Q* W5 e/ d' z 可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。
, z( w' p( i5 N: `7 u4 w
" g9 i0 j) J; D 例如:以二进制输入方式打开文件c:\config.sys1 Y* L# t. ]! ~# O" T n; c! @
4 o5 j2 V3 `" @- a" v
fstream file1;
& ?% A' q0 i" g' N 3 ^( ]2 y1 _! z) X. }& r& Z
file1.open("c:\\config.sys",ios::binary|ios::in,0);6 |2 P, |( s" r& Y, \! n
, b' j0 m3 ~5 V+ _2 [2 [% |: T [ 如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
: H" }! b; w4 \3 [ F
& C8 B7 ?$ `" }4 L' Y file1.open("c:\\config.sys"); <=> file1.open("c:\\config.sys",ios::in|ios::out,0);, d8 r4 l3 V, a3 p
+ @5 i# H* _; ^4 q! P2 F) J
另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
4 Y$ f m/ o% F6 A1 @
( u( O' T% K+ F! |. ?( V fstream file1("c:\\config.sys"); 特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
, B( t# Y" D! r2 Q! ?; q- S) M z
& b3 L* H. B. U @5 {7 F ifstream file2("c:\\pdos.def");//以输入方式打开文件
V/ @! D- D2 ?/ v; a
% b2 v7 i) F6 X5 C2 h8 U3 w7 }! | ofstream file3("c:\\x.123");//以输出方式打开文件 所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。+ e1 x3 j7 w2 H6 {# j4 p7 a
, a& s3 ^% A, a7 w, s 二、关闭文件
7 |5 T2 H. b- K% {. y& B7 n
8 Y7 B6 W' e7 O; _+ ^ @3 J' t 打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。
: l* E% O# o' ?. V! R7 _
- e" ]7 \4 s- F 三、读写文件. ~9 I8 j! T9 d; V. U, A# d
- r4 ~4 o( S: x. D q1 v
读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式. o$ f8 A* A4 \
5 ~2 o4 Q: M5 m7 c/ P1 h 1、文本文件的读写
, i+ l2 \# U& W i+ a2 h
6 q, k/ d' ~+ N6 }0 A! v+ K" u 文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:3 z" Z2 N0 ^& u/ f0 I
# @% Q/ k, i! [$ g8 [+ f9 d, ^8 Z
file2<<"I Love You";//向文件写入字符串"I Love You"
8 c ` @/ ?& v6 L. ^/ R 6 a& j: O- v6 v
int i;
8 f' k/ J% U+ g) N / A- X5 d: \2 B4 M; m
file1>>i;//从文件输入一个整数值。0 {6 p% o) G+ }7 {
( O' L' l, A5 {& u$ j3 M" H2 {
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
. a% w- i6 s7 l! i4 c- k3 h a$ | {3 t y# d& A( ~2 T
操纵符 功能 输入/输出( Q0 T v# }- N' u# P. W& s
( S x# u1 h. p/ U6 r, D9 E
dec 格式化为十进制数值数据 输入和输出4 a5 b- C" d3 g. q V1 y) R
2 S* i' r7 f, f! _$ m% M n
endl 输出一个换行符并刷新此流 输出: P$ o) Z B3 I& a6 ?
- x3 p5 L, F' V6 v+ X6 `0 H
ends 输出一个空字符 输出! L. v7 J' `$ v$ H! p' g
( ]1 z- e+ [9 B9 y hex 格式化为十六进制数值数据 输入和输出
; i4 [8 B3 C4 Z' \; k
9 d7 n' r3 T6 v+ v9 B( l oct 格式化为八进制数值数据 输入和输出
$ A/ \4 v# t. M. @- @$ } % z; H5 u4 A* e! M! g9 ^( `. _
setpxecision(int p) 设置浮点数的精度位数 输出! \0 p9 u4 _8 k
; L- t1 {' Y+ j7 C. D! a. v; E 比如要把123当作十六进制输出:file1<
; \4 W, g0 p1 j9 L 2、二进制文件的读写
$ D0 z+ N; ?2 t
- I2 N: N& _2 R. E- s. H ①put()6 s. k5 o9 ^2 @0 j. h: q3 R
+ a$ K+ r' `$ U9 d+ i
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
) I& a1 X% v% E0 d- d6 C
) A6 K$ W, E% K1 X) l5 G# S- B6 M ②get()5 P: t$ _; q& T& K* H$ P, w" l- m
0 m& H( |1 z7 q# Q! Q get()函数比较灵活,有3种常用的重载形式:7 a* r6 K3 n* ^8 b5 t) M
8 D) K+ d# k: [ Y3 \8 ^0 o 一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
0 p) H5 q* W3 \8 ]
* W2 s0 Q4 Q1 f$ N9 L+ z 另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。7 w' }3 L; G8 I1 L8 A5 [
6 M7 k5 S$ k* P; P. q$ T
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:9 B$ u7 J |: E2 y# a
i/ |- u9 ]' ~, Y- _; g. L4 P( k
file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。 j9 h# ^' g6 {/ x; X! H
* b- `9 C8 ?' v) z
③读写数据块
! L/ O5 c$ P# O6 B' M9 o* u
1 n, @+ i( R C% F# x; H8 b* [/ R 要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:* Z7 ~/ K( B& K. e8 K' a
8 j d- S& |4 I
read(unsigned char *buf,int num);
; M" g, m Y( K v. w$ u G3 a9 Y9 n& j
write(const unsigned char *buf,int num);# o4 _& D: q5 B8 A3 X- t' ~! I) e$ l) t
) w& S, F! ]4 I! h! _$ v
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。6 }9 U" }0 q- k! s) {
# N% l3 v, f8 `' ]( M) @0 w- ~
例:6 I* S, C3 q% {9 z% @; C0 M, E
! }3 F; Z T& X2 Z unsigned char str1[]="I Love You";5 p5 Y) N+ Q( q
3 W! G' c$ _- D int n[5];$ F9 H$ x _( I6 l$ i, i
$ N6 v8 l: |; s% _+ \* D. w7 Z ifstream in("xxx.xxx");
7 ^( T7 X+ E! w 7 W1 n7 J% d: q! ~' ~8 T
ofstream out("yyy.yyy");
' |3 v$ B( r) c6 `8 p: ?. l# A( g & E7 |4 W ^- @+ y8 { j
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中0 w- `7 Q8 x5 k; a3 c4 g' V
: ^4 P$ O; X, l( u# S
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
/ |4 Y7 d: z: V( K
" w1 h; P9 O+ D9 K/ f; n& x$ t/ G% {1 } in.close();out.close(); 四、检测EOF: D0 P" [" I; p* g4 a
9 g! {( c) P( t) W
成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
* l' @( d# e) a1 I# X 8 A4 ]) f5 n% c
例: if(in.eof()) ShowMessage("已经到达文件尾!");7 L# a: S; x" |3 w$ ^8 P* u
7 Z/ y2 y" [" ]+ a" t2 m9 @
五、文件定位# Z( O& P5 D5 E* s u* g
& _9 L1 V Y' _' a8 G3 m
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:: ?8 C) A; _" \( [" o
9 T+ a# b5 D7 r; G8 Z
istream &seekg(streamoff offset,seek_dir origin);
) }# o, F. t9 |+ p
! A! E/ i' H' v- { ostream &seekp(streamoff offset,seek_dir origin);
5 F$ p3 X. ^9 k/ V4 u( }" Z
3 D' }/ @4 o) }8 m streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
6 v1 q# c9 ]% l6 k" X7 g) q4 o $ u) c& f) @3 J D) T# R& r* L, h, ~
ios::beg: 文件开头& M% Q. Q1 R1 H" O
: `0 M9 S( c3 h( A ios::cur: 文件当前位置
8 D# y6 d' I; ?6 H 2 l- i3 M* J, q# W% ^% s" b
ios::end: 文件结尾
+ i% n! ?5 s' m" V
" R% a2 O/ f$ r+ W4 n- W* \, z7 a 这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:/ l9 K; Z5 a. p- z
9 c- `. _2 J- f0 y4 m2 c: J
file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节
8 ~* U/ _9 ?0 A, D5 G9 X1 c& ] & R! ]2 W* N! H* H( z
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
% V8 v& W5 C' S5 L( d3 _$ q' p% R# E" p. C9 ?+ A
|
|