第 10章 输入 /输出流
10.1 输入 /输出流概述
10.2 插入运算符及提取运算符
10.3 格式化输入输出
10.4 文件的输入输出
10.5 输入输出文件流 fstream
10.1 输入 /输出流概述
10.1.1 流的概念
“流” 是一种抽象的形态,指的是计算机里的 数据从一个对象流向另一个对象 。这里数据流入和流出的对象通常是指计算机中的屏幕、内存、文件等一些输入输出设备。数据的流动就是由
I/O流类来实现的。
如预定义流对象 cin和 cout实现的数据流动过程:
C++中的 I/O流负责建立程序与设备对象之间的连接,它像一个桥梁,沟通了数据的产生者和消费者,使他们之间产生数据的流动 。
第 10章 输入 /输出流内存 数据流 显示器流对象 cout
键盘 数据流 内存流对象 cin
10.1 输入 /输出流概述
10.1.2 流类库的结构第 10章 输入 /输出流
streambuf
filebuf strstreambuf stdiobuf
ostream
ios
istream
iftream istrstream istream_withassign oftream ostrstream ostream_withassign
iostream
fstream strstream stdiostream
Iostream_init
第 10章 输入 /输出流类 名 说 明 包含头文件抽象流基类
ios 所有输入输出流类的基类 ios.h
输入流类
istream 通用输入流类和其他输入流的基类 iostream.h
ifstream 输入文件流类 fstream.h
istrstream 输入字符串流类 strstrea.h
istream_withassign cin的输入流类 iostream.h
输出流类
ostream 通用输出流类和其他输出流的基类 iostream.h
ofstream 输出文件流类 fstream.h
ostrstream 输出字符串流类 strstrea.h
ostream_withassign cout,cerr,clog的输出流类 iostream.h
I/O流类说明表输入输出流类
iostream 通用输入 /输出流类和其他输入 /输出流类的基类
iostream.h
fstream 输入 /输出文件流类 fstream.h
strstream 输入 /输出字符串流类 strstrea.h
stdiostream 标准 I/O文件的输入输出类 stdiostr.h
流缓冲区类
streambuf 抽象流缓冲区基类 iostream.h
filebuf 磁盘文件的流缓冲区类 fstream.h
strstreambuf 字符串的流缓冲区类 strstrea.h
stdiobuf 标准 I/O文件的流缓冲区类 stdiostr.h
预先定义的流初始化类
Iostream_init 初始化预定义流对象的类 iostream.h
第 10章 输入 /输出流
I/O流类说明表(续)
10.1 输入 /输出流概述
10.1.2 流类库的结构(续)
流类库中与文件输入输出相关的文件流类结构:
第 10章 输入 /输出流
ios
istream ostream
ifstream ofstreamiostream
fstream
返 回
10.2 插入运算符与提取运算符
1,插入运算符插入运算符,<<‖:通常用于 插入数据到一个输出流对象 中,流对象再进一步将数据输出到它所关联的设备中 。
如,cout << ―Hello World!‖
插入运算符,<<‖适用于任何输出流对象,如输出文件流
ofstream的对象等。,<<‖右侧可以是任何标准数据类型的变量及常量,也可以是字符串变量及常量。
如,cout << i <<?s‘ << 3.14 <<? ‘ << f ;
第 10章 输入 /输出流
10.2 插入运算符与提取运算符
2,提取运算符提取运算符,>>‖,通常用于从输入流对象中提取数据 。
如,int i; char buf[100];
cin >> i ;
cin >> buf ;
提取运算符,>>‖适用于任何输入流对象,如输入文件流
ifstream的对象等。,>>‖右侧可以是任意标准数据类型的变量,
也可以是字符串变量。
注意,使用提取运算符,>>‖提取数据时,以空白符 (如空格、
回车,tab) 作为数据的分割符,因此提取字符串数据时,不能提取空白字符。
第 10章 输入 /输出流返 回
10.3 格式化输入输出
C++中的 I/O流可以完成输出 /输入的格式化操作,如设臵域宽、
设臵精度及整数进制等。
设臵输入输出格式的方法:
使用流操纵元,只需把流操纵元插入(提取)到输出流(输入流)中即可对输出流(输入流)进行格式化,如 setiosflags、
setw,setfill,setprecision,hex,oct等,使用流操纵元时需在程序中包含头文件 iomanip.h
通过流的成员函数,即由流对象直接调用完成格式化,如
setf,unsetf,width,fill,precision等。使用流成员函数的优点是在设臵格式同时,可以返回以前的设臵,便于恢复原来的设臵。
第 10章 输入 /输出流
10.3 格式化输入输出
10.3.1 输出宽度控制,setw和 width
使用 流操纵元 setw和 成员函数 width可以控制当前 域宽 (即输入 /输出的字符数)。
注意:
(1) 宽度的设臵 仅适用于下一个 插入或读取的 数据 。
(2) 在输出流中控制域宽,如果输出数据的宽度比设臵的域宽小,将以 默认右对齐 方式输出数据,左边空位会用填充字符来填充( 填充字符默认是空格 )。
(3) 如果输出数据的宽度比设臵的宽度大,数据不会被截断,
将输出所有位数。
第 10章 输入 /输出流例 10.1 使用 setw操纵元控制域宽
# include <iostream.h>
# include <iomanip.h>
void main( )
{
cout << 123 << endl;
cout << setw(5) << 4.5 << 6.7 << endl;
}
程序运行结果为:
123
4.56.7
第 10章 输入 /输出流域宽仅适用于下一个数据;
实际数据比设置的域宽小,将右对齐,左补空格例 10.2 使用 width成员函数控制域宽
# include <iostream.h>
void main( )
{
char * str[3] = {“abc”,“abcde”,“abcdef”};
for (int i = 0; i < 3; i ++ )
{
cout.width(5);
cout <<str[i] <<endl;
}
} 程序运行结果为:
abc
abcde
abcdef
第 10章 输入 /输出流
10.3 格式化输入输出
10.3.2 填充字符控制,setfill和 fill
在缺省情况下,如果域宽大于数据宽度时,填充多余空间的字符是空格 。 如果要改变填充字符,可以使用 流操纵元 setfill和 成员函数 fill。
注意,设臵了填充字符后,将对程序后面的输出代码产生永久影响,直到下一次再改变填充字符为止 。
第 10章 输入 /输出流例 10.3 使用 setfill控制填充字符
# include <iostream.h>
# include <iomanip.h>
void main( )
{
double values[ ] = {1.23,15.16,653.7,4358.24};
cout << setfill(?*?) ;
for ( int i = 0 ; i < 4 ; i ++ )
cout << setw(10) << values[i] << endl;
}
程序运行结果为:
123
4.56.7
第 10章 输入 /输出流此语句也可以改为:
cout.fill(?*?);
fill()成员函数将返回设置前的填充字符
10.3 格式化输入输出
10.3.3 输出精度控制,setprecision和 precision
使用 流操纵元 setprecision以及 成员函数 precision可以控制浮点数输出的精度 。
注意,精度一旦设臵,就可以用于 以后所有输出的数据,直到下次精度发生改变 。
使用成员函数 precision可以返回设臵前的精度 。
第 10章 输入 /输出流例 10.4 控制浮点数精度
# include <iostream.h>
# include <iomanip.h>
void main( )
{
double value = 31.4142743;
int Preprecision = cout.precision(4);
cout << value << endl;
cout << setprecision( Preprecision ) << value << endl;
}
程序运行结果为:
31.41
31.4143
第 10章 输入 /输出流通过 precision成员函数设置精度后,将以前精度值返回并保存在变量 Preprecision中。
注意,系统默认精度为 6,
恢复原来的精度设置
10.3 格式化输入输出
10.3.3 输出精度控制(续)
所设臵的精度值,在程序 没有设臵计数法 情况下,表示 浮点数的有效数字的个数 。 若程序 设臵了计数法 ( ios::fixed 或
ios::scientific),则表示 小数点后数字的个数 。
ios::fixed 表示以 定点法 输出浮点数 ( 不带指数 ) 。
ios::scientific 表示以 科学计数法 输出浮点数 。
第 10章 输入 /输出流例 10.4 (续一)
# include <iostream.h>
# include <iomanip.h>
void main( )
{
double value = 31.4142743;
cout << setiosflags( ios::fixed );
int Preprecision = cout.precision(4);
cout << value << endl;
cout << setprecision( Preprecision ) << value << endl;
}
程序运行结果为:
31.4143
31.414274
第 10章 输入 /输出流设置计数法:以定点法输出浮点数例 10.4 (续二)
# include <iostream.h>
# include <iomanip.h>
void main( )
{
double value = 31.4142743;
cout << setiosflags( ios::scientific );
int Preprecision = cout.precision(4);
cout << value << endl;
cout << setprecision( Preprecision ) << value << endl;
}
程序运行结果为:
3.1414e+001
3.141427e+001
第 10章 输入 /输出流设置计数法:以科学计数法输出浮点数
10.3 格式化输入输出
10.3.4 其他格式状态上例中的 setiosflags 也是一个 流操纵元,定义在头文件
<iomanip.h>中 。
通过将 setiosflags的参数 设臵为各种不同 流格式状态标志值,可以对相应的输入输出格式进行控制 。
若需要同时设臵多个标志位时,可以使用 按位或运算符 ( |) 将不同的标志项结合 。
第 10章 输入 /输出流第 10章 输入 /输出流流格式状态标志 说 明
ios,,skipws
ios,,left
ios,,right
ios,,internal
ios,,dec
ios,,oct
ios,,hex
ios,,showbase
ios,,showpoint
ios,,uppercase
ios,,showpos
ios,,scientific
ios,,fixed
跳过输入流的空白字符在输出域中左对齐输出,必要时,在右边填充字符在输出域中右对齐输出,必要时,在左边填充字符(默认)
在输出域中左对齐数值的符号及进制符号,右对齐数字值以十进制形式格式化指定整数(默认)
以八进制形式格式化指定整数以十六进制形式格式化指定整数在数值前输出进制( 0表示八进制,0x或 0X表示十六进制)
输出浮点数时显示小数点和尾部的 0
输出十六进制数时显示大写字母 A~F,科学计数法显示大写 E
输出正数时前面加正号( +)
以科学计数法显示浮点数以定点表示法显示浮点数
I/O流格式状态标志例 10.5 使用 setiosflags控制流格式
# include <iostream.h>
# include <iomanip.h>
void main( )
{
int x = 200;
cout << setiosflags(ios,,internal | ios,,showpos );
cout << setw(10) << x << endl;
cout << setiosflags(ios,,hex| ios,,uppercase | ios,,showbase) ;
cout << setw(10) << x << endl;
cout << oct << setw(10) << x << endl;
}
第 10章 输入 /输出流将 oct直接插入流中,也可使用:
setiosflags(ios::oct)
程序运行结果为:
+ 200
0X C8
0 310
10.3 格式化输入输出
10.3.4 其他格式状态(续)
使用流操纵元 setiosflags设臵相应的标志位后,对流对象产生的 影响是持久的,若想 恢复以前的默认设臵,可以通过
resetiosflags流操纵元 关闭相应的标志位。
如:
cout << resetiosflags( ios,,internal | ios,,showbase);
可以取消对域中对齐格式的设臵,同时取消显示数制标志,
恢复系统默认格式。
第 10章 输入 /输出流返 回
10.4 文件的输入输出处理文件输入输出的流类主要有 ofstream,ifstream和 fstream三个类 。 均定义在 fstream.h中 。
向文件 输出数据 即将数据保存到文件中时,要使用 ofstream类;
从文件中 读取数据 即从文件中输入数据时,要使用 ifstream类 。 而使用 fstream类可以同时进行 输入及输出 操作 。
文件输入输出的一般步骤为:
创建流对象并打开文件 → 读写文件 → 关闭文件第 10章 输入 /输出流
10.4 文件的输入输出
10.4.1 打开文件
1,使用默认构造函数,然后调用 open函数
用法如下:
文件 I/O流类名 流对象名; //声明一个流对象流对象名,open(文件名,打开方式 ); //调用 open函数打开文件如,ofstream my_file;
my_file.open(―boot.ini‖,ios::out);
参数“文件名”:用于指定要打开文件的文件名
– 若为不带路径的文件名表示与当前应用程序在同一文件夹
– 若带路径的文件名,注意?\‘应用?\\‘表示第 10章 输入 /输出流
10.4 文件的输入输出
10.4.1 打开文件(续一)
参数“打开方式 ‖:用于指定文件的打开方式第 10章 输入 /输出流打开方式 说 明
ios,,in
ios,,out
ios,,app
ios,,ate
ios,,nocreate
ios,,noreplace
ios,,trunc
ios,,binary
打开一个输入文件,是 ifstream对象的默认方式打开一个输出文件,是 ofstream对象的默认方式。若打开一个已有文件
,则删除原有内容,若打开的文件不存在,则将创建该文件。
打开一个输出文件,用于在文件末尾添加数据,不删除文件原有内容打开一个现有文件(用于输入或输出),并定位到文件结尾仅打开一个存在的文件(不存在则失败)
仅打开一个不存在的文件(存在则失败)
打开一个输出文件,如果它存在则删除文件原有内容以二进制模式打开一个文件(默认是文本模式)
10.4 文件的输入输出
10.4.1 打开文件(续二)
2,在构造函数中直接指定文件名及打开方式
用法如下:
文件 I/O流类名 流对象名 (文件名,打开方式 );
如,ifstream infile ( ―D:\\hello.dat‖,ios::binary );
第 10章 输入 /输出流如果使用以上两种方法打开文件不成功 (如文件路径不正确),
文件流对象将为 0,因此习惯上可用如下方式判断打开操作是否失败:
if( ! my_file) { …… } // 如果打开文件的操作不成功
10.4 文件的输入输出
10.4.2 写入文件如果写入的是 标准数据类型的数据或字符串,可以直接通过插入运算符( <<),将数据插入到输出文件流对象中。
如:
ofstream my_file ( ―D:\\data.txt‖,ios::out );
my_file << ―Hello!‖ <<? ‘<< 234 << endl;
使用 插入运算符 在写入数据时仅局限于标准数据类型及字符串,对于 自定义类型的数据并不能直接插入 。
第 10章 输入 /输出流空格,是为了在文件中将数据分隔开,以便在读出时能正确区分数据。
10.4 文件的输入输出
10.4.2 写入文件(续一)
1,put函数,使用 put函数可以将一个单个字符写入流对象,进而写入流对象所关联的文件中。 put函数每次只能写一个字符。
用法如下:
my_file.put(?A‘);
char ch =?A‘;
my_file.put(ch);
注意,使用 put函数输出数据不受格式影响,即设臵的域宽和填充字符对于 put函数不起作用。
第 10章 输入 /输出流
10.4 文件的输入输出
10.4.2 写入文件(续二)
2,write函数,把内存中的一块内容写入输出流对象中。主要用于输出数组及自定义类型变量等具有连续内存的数据。
write函数的第一个形参:
用于指定输出数据的 内存起始地址,该地址为字符型( char
*),因此传递的实参应为 字符型的指针 。
write函数的第二个形参:
用于指定所 写入的字节数,即从该起始地址开始写入多少字节的数据,第二个形参 类型为整型 。
第 10章 输入 /输出流例 10.6 使用 write函数输出 CRect类的对象
# include <fstream.h>
void main()
{
CRect r;
r.SetColor(―Red‖);
r.Move(10,20);
r.SetSize(100,200);
ofstream outfile (―D:\\a.txt‖,ios::out);
outfile.write( (char *) &r,sizeof(r) );
outfile.close(); //调用 close函数关闭文件
}
第 10章 输入 /输出流定义输出文件流对象并打开文件进行输出将 r地址强制类型转换 (char *)为字符型指针例 10.7 使用 write函数输出整型数组
# include <fstream.h>
void main()
{
int array[ ] = {35,42,57,88,69,75};
ofstream outfile2(―D:\\a.txt‖,ios::app);
outfile2.write( (char *) array,sizeof(array) );
outfile2.close();
}
第 10章 输入 /输出流在打开的文件尾添加数据将数组首地址强制类型转换若将主函数的 array数组改为,char array[ ] =,hello world!”;
则 write语句将变为,outfile2.write( array,sizeof (array) );
无须强制类型转换
10.4 文件的输入输出
10.4.3 读取文件如果读取的是 标准数据类型的数据或字符串,可以直接通过提取运算符( >>),将数据从输入文件流对象读取到程序的变量中。
使用提取运算符提取数据时,将以 空白字符 (如空格,Tab、
回车)作为数据之间的 分隔符,因此这些空白字符不能被作为数据提取出来。
如,char s[10]; int i;
ifstream in_file ( ―D:\\data.txt‖,ios::in );
in_file >> s >> i;
第 10章 输入 /输出流若文件中数据为:
Hello! 234
则 s和 i的数据分别为:,Hello!”,234
10.4 文件的输入输出
10.4.3 读取文件(续一)
1,get函数,使用 get函数可以从流对象中提取一个单个字符,
get函数弥补了提取运算符不能提取空白字符的缺点,它能把任意字符包括空白符提取出来。
get函数提取一个字符时,有带形参和不带形参两种形式:
如,char ch ;
ch = cin.get();
或:
cin.get(ch);
若以上语句中调用 get函数的是一个输入文件流对象,则将从该流对象所关联的文件中提取出单个字符。
第 10章 输入 /输出流
10.4 文件的输入输出
10.4.3 读取文件(续二)
2,getline函数,用于从流对象中 提取多个字符,通常用于提取一行字符。 get函数有三个形参。
get函数的第一个形参:
为 字符型指针 ( char *),用于 存放读出的多个字符,通常传递的实参为字符数组。
get函数的第二个形参:
为整型,用于指定本次读取的 最大字符个数 。
get函数的第三个形参:
为字符型,默认值为回车符 (‘ \n‘),用于指定分隔字符,
作为一次读取结束的标志。
第 10章 输入 /输出流例 10.8 读取文件 E:\boot.txt中的内容,并输出到屏幕上
# include <fstream.h>
# include <iostream.h>
void main()
{
char array[100];
ifstream ifs( ―E:\\boot.txt‖,ios::nocreate );
if(!ifs) return; //如果文件不存在,打开不成功,则结束程序
while ( !ifs.eof() ) //eof函数用于判断是否到文件尾,到文件尾返回 True
{
ifs.getline(array,100); //100表示每次读取字符的个数最多为 99个
cout << array << endl;
}
ifs.close();
}
第 10章 输入 /输出流使用 getline函数按行读取文件中的数据,
每次读取一行时,遇回车符或达到最大字符个数,则结束,并将读出数据保存于数组 array中。
10.4 文件的输入输出
10.4.3 读取文件(续三)
3,read函数,从流对象中提取整块数据到变量中,主要用于提取数据到数组及自定义类型变量中。
read函数的第一个形参:
用于 保存读出的数据,类型为 字符型指针 ( char *),与 write
函数中用法一致。
read函数的第二个形参:
用于指定 读出多少个字节,类型为整型 。与 write函数中用法一致。
第 10章 输入 /输出流例 10.9 读取例 10.6中输出到文件,D:\a.txt”中的内容,并将矩形参数显示到屏幕上
# include <fstream.h>
# include <iostream.h>
void main()
{
CRect r2;
ifstream ifile (―D:\\a.txt‖);
ifile.read( (char *) &r2,sizeof(r2) ); //将读出的数据保存到矩形对象 r2中
ifile.close();
r2.Draw();
}
第 10章 输入 /输出流程序运行结果为:
矩形左上角坐标为( 20,10)
矩形长和宽分别为 100,200
矩形的颜色是 red
10.4 文件的输入输出
10.4.4 文件读写位臵指针位置指针,用于保存在文件中 进行读或写的位臵 。通过对位臵指针的操作,适当地调整读或写的位臵,可以实现对磁盘文件的随机访问。
与 ofstream对应的是 写位臵指针,指定下一次写数据的位臵。
相关的操作函数为:
seekp函数:用于移动指针到指定位臵。
tellp函数:用于返回指针当前的位臵。
与 ifstream对应的是 读位臵指针,指定下一次读数据的位臵。
相关的操作函数为:
seekg函数:用于移动指针到指定位臵。
tellg函数:用于返回指针当前的位臵。
第 10章 输入 /输出流
10.4 文件的输入输出
10.4.4 文件读写位臵指针(续)
seekg函数的使用形式( seekp类似):
seekg(n):用于移动指针到文件第 n个字节后。
seekg(n,ios::beg):从文件起始位臵向后移动 n个字节。
seekg(n,ios::end):从文件结尾位臵向前移动 n个字节。
seekg(n,ios::cur),从当前位臵向前或向后移动 n个字节。
其中,n=0,在指定位臵 ; n>0,在指定位臵向后移动 ; n<0,在指定位臵向前移动。
tellg函数的使用形式( tellp类似):
streampos n = 流对象,tellg()
streampos可看作整型数据,返回值保存指针当前的位臵。
第 10章 输入 /输出流例 10.10 已知文件 data.txt中存有 10个 CRect对象的数据,
现要求读取最后一个对象,把它的左上角坐标修改为( 100,
100),其他不变,修改后写回到文件中去。
#include <fstream.h>
void main()
{
CRect rt;
ifstream ifs(,data.txt” );
ifs.seekg( 0,ios::end ); //将指针移动到文件尾
streampos lof = ifs.tellg(); //求得文件长度 lof
ifs.seekg( -lof/10,ios::end ); //将指针移动到最后一条记录起始位臵
ifs.read( (char *)&rt,sizeof(CRect) );
ifs.close();
rt.Move(100,100);
ofstream ofs(,data.txt”,ios::ate ); //以 ios::ate方式打开文件防止删除原来内容
ofs.seekp( -lof/10,ios::end ); //将指针移动到最后一条记录起始位臵
ofs.write( (char *)&rt,sizeof(CRect) );
ofs.close();
}
第 10章 输入 /输出流
10.4 文件的输入输出
10.4.5 错误处理函数
eof() —— 如果输入流结束,到文件尾,则返回 True;
bad() —— 如果出现一个严重的、不可恢复的错误,如由于非法操作导致数据丢失、对象状态不可用等,则返回 True,通常这种错误不可修复,此时不要对流再进行 I/O操作;
fail() —— 如果某种操作失败,如打开操作不成功,或不能读出数据,或读出数据的类型不符等等,则返回 True;
good() —— 如果以上三种错误均未发生,表示流对象状态正常,则返回 True。
以上函数可由流对象直接调用,如:
if(!inf.eof()) //如果没有到文件末尾,if条件满足第 10章 输入 /输出流
10.4 文件的输入输出
10.4.6 关闭文件文件使用完毕后必须将其关闭才能断开流和对象之间的联系。
文件关闭后,还可以再次与流对象关联,打开文件进行输入或输出操作。
使用流对象的 close函数 可以完成关闭文件的操作,close函数无形参,调用形式为:
流对象,close();
第 10章 输入 /输出流返 回
10.5 输入输出文件流 fstream
fstream类,对文件同时进行读写,它将输入和输出流的功能集于一身。
使用 fstream打开文件的方法:
fstream iofile( ―myfile.dat‖,ios::in | ios::out );
注意,必须指定打开方式,因为没有默认值。
在使用 fstream的对象读写文件时,可以联合使用 seekg和
seekp函数对指针进行定位,调整正确的读写位臵 。
第 10章 输入 /输出流例 10.11 打开文件,E:\myfile.txt‖进行读写,首先读出文件内容,显示出来,再将内容写入原文件结尾,并将写入后的文件内容显示出来。
# include<fstream.h>
# include<iostream.h>
void main()
{
fstream iofile( ―E:\\myfile.txt‖,ios::in | ios::app );
iofile.seekg( 0,ios::end ); //定位至文件尾
streampos lof= iofile.tellg(); //获取文件长度
char *data;
data = new char[lof]; //动态分配内存用于保存文件内容
iofile.seekg( 0,ios::beg ); //定位至文件头
iofile.read( data,lof ); //将文件内容读到 data指向的内存中
cout << ―原文件内容为:” << endl;
第 10章 输入 /输出流例 10.11 (续)
for( int i =0; i<lof; i++ )
cout << data[i]; //逐个输出 data指向内存中的字符
cout << endl;
iofile.write( data,lof ); //打开方式为 ios::app,能将读出内容写入文件尾
delete [] data;
iofile.seekg( 0,ios::end );
lof = iofile.tellg();
data = new char[lof];
iofile.seekg( 0,ios::beg );
iofile.read( data,lof );
cout << ―读写操作后文件内容为:” << endl;
for(i =0; i<lof; i++ )
cout << data[i];
cout << endl;
iofile.close();
delete [] data;
}
第 10章 输入 /输出流程序运行结果为:
原文件内容为:
abcdefghi
读写操作后文件内容为:
abcdefghiabcdefghi 返 回谢 谢!