C++中的IO流——郭炜
目录
- IO流类
- 输入输出的重定向
- 判断输入流结束
- IO流常用函数
- IO流的错误状态字
- 流操纵算子
- 文件读写
- 创建文件
- 文件名的绝对路径和相对路径
- 文件读写指针
- 二进制文件读写
- 读写的基本操作
- 例子
- 扩展知识
IO流类

istream是用于输入的流类,cin就是该类的对象。
ostream是用于输出的流类,cout就是该类的对象。
ifstream是用于从文件读取数据的类。
ofstream是用于向文件写入数据的类。
iostream是既能用于输入,又能用于输出的类。
fstream 是既能从文件读取数据,又能向文件写入数据的类。输入流对象: cin 与标准输入设备相连输出流对象:cout 与标准输出设备相连cerr 与标准错误输出设备相连//这两个在缺省的情况下,和cout一样clog 与标准错误输出设备相连
输入输出的重定向
//输出重定向
#include
using namespace std;
int main() {int x,y;cin >> x >> y;freopen("test.txt","w",stdout); //将标准输出重定向到 test.txt文件if( y == 0 ) cerr << "error." << endl;//用法:当cout重定向之后,还想输出到屏幕上就用这个else cout << x /y ; //输出结果到test.txtreturn 0;
}//输入重定向
#include
using namespace std;
int main() {double f; int n;freopen(“t.txt”,“r”,stdin); //stdin是标准输入,cin被改为从 t.txt中读取数据cin >> f >> n;//不会等待用户输入,直接用文件中读出cout << f << "," <<n << endl;return 0;
}
判断输入流结束
//输入流是一个输入的来源,可以是键盘,可以是一个文件
int x;
while(cin>>x){//这里涉及到一个强制类型转换运算符的重载
…..
}
return 0;//文件输入流:读到文件尾部,输入流就算结束
freopen(“some.txt”,”r”,stdin);
//键盘输入流:在单独一行输入Ctrl+Z代表输入流结束
IO流常用函数
getline()
//istream类的成员函数
istream & getline(char * buf, int bufSize);从输入流中读取bufSize-1个字符到缓冲区buf,或读到碰到‘\n’————默认回车为止(哪个先到算哪个)。
istream & getline(char * buf, int bufSize,char delim);//delim为分隔符从输入流中读取bufSize-1个字符到缓冲区buf,或读到碰到delim字符为止(哪个先到算哪个)//getline还有一个全局函数,第一个位置的参数是输入流
注意:两者一个是char* 一个是string类型!
istream& getline (istream& is, string& str, char delim );
istream& getline (istream& is, string& str);string s
getline(cin,s);//将从键盘输入的放到s中
//两个函数都会自动在buf中读入数据的结尾添加\0
//‘\n’或delim都不会被读入buf,但会被从输入流中取走,即删除了。//如果输入流中‘\n’或delim之前的字符个数达到或超过了bufSize个,就导致读
//入出错,其结果就是:虽然本次读入已经完成,但是之后的读入就
//都会失败了。//可以用 if(!cin.getline(…)) 判断输入是否结束
.
其他函数
bool eof(); 判断输入流是否结束
char peek(); 返回下一个字符,但不从流中去掉.
istream & putback(char c); 将字符ch放回输入流//放到输入流的头部,键盘输入流会怎么样呢
istream & ignore( int nCount = 1, int delim = EOF );
从流中删掉最多nCount个字符,遇到EOF时结束。
gcount()函数无参函数,统计最后一次输入操作读取的字符数
istream& get(char*pch,int nCount,char delim=',');
唯一不同的是getline函数从输入流中输入一系列字符时包括分隔符,而get函数不包括分隔符。
IO流的错误状态字
在ios类中定义了一个数据成员,称为状态字。
其各位的状态由在ios类中定义的一些常量描述,这些常量及其含义如下图所示

1.检查一个流对象当前状态的成员函数
有几个函数可用来检查一个流对象的当前状态,它们都是ios类的成员函数:
int rdstate() //返回当前的流状态字
int eof() //如果提取操作已到达文件尾,则返回非零值
int fail() //若failbit位置位,返回非零值
int bad() //若badbit位置位,返回非零值
int good() //若状态字没有置位,则返回非零值
可以使用这些函数检查当前流的状态。例如:
ifstream istrm("my.data");
if(istrm.good())//状态在没有置位就是没有错误cin>>data; //文件被成功打开,可读入数据2.清除/设置流状态位函数
ios类的成员函数:
void ios::clear(int=0);
用于清除/设置流的状态位(它不能设置/清除hardfail位)
函数clear()更多地是用于在己知流发生错误的情况下清除流的错误状态,也可以用于设置流的错误状态
流操纵算子

//综合的一个例子
int main() {
int n = 141;
//1) 分别以十六进制、十进制、八进制先后输出 n
cout << "1) " << hex << n << " " << dec << n << " " << oct << n << endl;
double x = 1234567.89,y = 12.34567;
//2) 保留5位有效数字
cout << "2) " << setprecision(5) << x << " " << y << " " << endl;//没有说明默认的就是非定点小数
//3) 保留小数点后面5位
cout << "3) " << fixed << setprecision(5) << x << " " << y << endl ;//用fixed声明定点小数输出
//4) 科学计数法输出,且保留小数点后面5位
cout << "4) " << scientific << setprecision(5) <<x << " " << y << endl ;
//5) 非负数要显示正号,输出宽度为12字符,宽度不足则用'*'填补
cout << "5) " << showpos << fixed << setw(12) << setfill('*') << 12.1
<< endl;
//6) 非负数不显示正号,输出宽度为12字符,宽度不足则右边用填充字符填充
cout << "6) " << noshowpos << setw(12) << left << 12.1 << endl;//左对齐
//7) 输出宽度为12字符,宽度不足则左边用填充字符填充
cout << "7) " << setw(12) << right << 12.1 << endl;//右对齐
//8) 宽度不足时,负号和数值分列左右,中间用填充字符填充
cout << "8) " << setw(12) << internal << -12.1 << endl;//internal填充的字符放在中间
cout << "9) " << 12.1 << endl;
return 0;
}
输出:
1) 8d 141 215
2) 1.2346e+006 12.346
3) 1234567.89000 12.34567
4) 1.23457e+006 1.23457e+001
5) ***+12.10000
6) 12.10000****
7) ****12.10000
8) -***12.10000
9) 12.10000
/*用户自定义的流操纵算子*/
ostream &tab(ostream &output){//返回值类型和参数类型固定return output << '\t';
}
cout << “aa” << tab << “bb” << endl;
输出:aa bb因为 iostream 里对 << 进行了重载(成员函数)
ostream & operator <<( ostream & ( * p ) ( ostream & ) ) ;该函数内部会调用p所指向的函数,且以 *this 作为参数//这个this就是指向当时的cout
hex 、dec 、oct 都是函数
文件读写
//cin、cout 能用的成员函数,文件的读写都可以使用
//因为来自同一个基类
创建文件
//通过定义一个ifstream/ofstream/fstream对象在构造函数中给出参数
ofstream outFile(“clients.dat”, ios::out|ios::binary); – clients.dat” 要创建的文件的名字– ios::out 文件打开方式– ios:out 输出到文件, 删除原有内容//也就是说写– ios::app 输出到文件, 保留原有内容,总是在尾部添加– ios::binary 以二进制文件格式打开文件
//也可以先创建ofstream对象,再用 open函数打开
ofstream fout;
fout.open("test.out",ios::out|ios::binary);//这里的方式默认是一个输出流
//判断打开是否成功:
if(!fout){ cout << “File open error!”<<endl;
}

文件名的绝对路径和相对路径
//文件名可以给出绝对路径:C盘哪里哪里
//也可以给相对路径:就是相对于上一层什么的
//没有交代路径信息,就是在当前文件夹下找文件
绝对路径: "c:\\tmp\\mydir\\some.txt"
相对路径:
"\\tmp\\mydir\\some.txt"
当前盘符的根目录下的tmp\dir\some.txt
"tmp\\mydir\\some.txt"
当前文件夹的tmp子文件夹里面的…..
"..\\tmp\\mydir\\some.txt"
当前文件夹的父文件夹下面的tmp子文件夹里面的…..
"..\\..\\tmp\\mydir\\some.txt"
当前文件夹的父文件夹的父文件夹下面的tmp子文件夹里面的…..
//..就是上一层文件夹
文件读写指针
//文件的读写指针
对于输入文件,有一个读指针;
对于输出文件,有一个写指针;
对于输入输出文件,有一个读写指针;
标识文件操作的当前位置, 该指针在哪里,读写操作就在哪里进行
//文件的读写是通过函数进行的,但这些函数本身并没有带位置信息//文件写指针
ofstream fout("a1.out",ios::app); //以添加方式打开,是以写的方式打开了一个文件
long location = fout.tellp(); //取得写指针的位置
location = 10;
fout.seekp(location); // 将写指针移动到第10个字节处
fout.seekp(location,ios::beg); //从头数location
fout.seekp(location,ios::cur); //从当前位置数location
fout.seekp(location,ios::end); //从尾部数location返回读指针当前指向的位置值streampos istream::tellg( )
该函数的功能是确定文件指针的当前位置。//文件读指针
ifstream fin(“a1.in”,ios::ate);
//打开文件,定位文件指针到文件尾,这样可以知道内容的长度
long location = fin.tellg(); //取得读指针的位置
location = 10L;
fin.seekg(location); // 将读指针移动到第10个字节处
fin.seekg(location,ios::beg); //从头数location
fin.seekg(location,ios::cur); //从当前位置数location
fin.seekg(location,ios::end); //从尾部数location
//location可以为负值,意思为在指定位置的前面多少个字节返回读指针当前指向的位置值streampos istream::tellg( )
该函数的功能是确定文件指针的当前位置。
二进制文件读写
读写的基本操作
//二进制读文件(输入流常用成员函数):
ifstream 和 fstream的成员函数:
istream& read (char* s, long n);
将文件读指针指向的地方的n个字节内容,读入到内存地址s,然后将文件读指针向后移动n字节 (以ios::in方式打开文件时,文件读指针开始指向文件开头)
get()//二进制写文件(输出流常用成员函数):
ofstream 和 fstream的成员函数:
istream& write (const char* s, long n);//常量指针
将内存地址s处的n个字节内容,写入到文件中写指针指向的位置,然后将文件写指针向后移动n字节
(以ios::out方式打开文件时,文件写指针开始指向文件开头, 以ios::app方式打开文件时,文件写指针开始指向文件尾部 )
put()
例子
注意函数参数的类型,必要是要做类型的转换!
int main() { ofstream fout("some.dat", ios::out | ios::binary);int x=120;fout.write( (const char *)(&x), sizeof(int) );//强制转换fout.close();ifstream fin("some.dat",ios::in | ios::binary);int y;fin.read((char * ) & y,sizeof(int));//强制转换fin.close();cout << y <<endl;return 0;
}
用ofstream写
#include
#include
using namespace std;
struct Student {//这个时候说的文件类型,意思是存放的数据是什么类型的char name[20];int score;
};
int main() {Student s;ofstream OutFile( "c:\\tmp\\students.dat",ios::out|ios::binary);while( cin >> s.name >> s.score ) OutFile.write( (char * ) & s, sizeof( s) );//这里的s本身就类似指针OutFile.close();return 0;
}
用ifstream读
#include
#include
using namespace std;
struct Student {char name[20];int score;
};
int main() {Student s;ifstream inFile("students.dat",ios::in | ios::binary );if(!inFile) {cout << "error" <<endl;return 0;}while( inFile.read( (char* ) & s, sizeof(s) ) ) {int readedBytes = inFile.gcount(); //看刚才读了多少字节cout << s.name << " " << s.score << endl; }inFile.close();return 0;
}
用fstream修改文件中的内容
#include
#include
using namespace std;
struct Student {char name[20];int score;
};
int main()
{Student s;fstream iofile( "c:\\tmp\\students.dat", ios::in|ios::out|ios::binary);if( !iofile) {cout << "error" ;return 0;}iofile.seekp( 2 * sizeof(s),ios::beg); //定位写指针到第三个记录iofile.write("Mike",strlen("Mike")+1);//这里为什么可以直接用字符串啊,还有为什么多保存一个/0iofile.seekg(0,ios::beg); //定位读指针到开头while( iofile.read( (char* ) & s, sizeof(s)) ) cout << s.name << " " << s.score << endl;iofile.close();return 0;
}
文件拷贝程序mycopy
mycopy src.dat dest.dat
即将 src.dat 拷贝到 dest.dat 如果 dest.dat 原来就有,则原来的文件会被覆盖
#include
#include
using namespace std;
int main(int argc, char * argv[]){if( argc != 3 ) {//保证命令行格式cout << "File name missing!" << endl;return 0;}ifstream inFile(argv[1],ios::binary|ios::in); //打开文件用于读if( ! inFile ) {cout << "Source file open error." << endl;return 0;}ofstream outFile(argv[2],ios::binary|ios::out); //打开文件用于写if( !outFile) {cout << "New file open error." << endl;inFile.close(); //打开的文件一定要关闭return 0;}char c;while( inFile.get(c)) //每次读取一个字符outFile.put(c); //每次写入一个字符outFile.close(); inFile.close();return 0;
}
扩展知识
二进制文件和文本文件的区别
Linux,Unix下的换行符号:‘\n’ (ASCII码: 0x0a)
Windows 下的换行符号:‘\r\n’ (ASCII码: 0x0d0a) endl 就是 ‘\n’
Mac OS下的换行符号: ‘\r’ (ASCII码:0x0d)
导致 Linux, Mac OS 文本文件在Windows 记事本中打开时不换行
Unix/Linux下打开文件,用不用 ios::binary 没区别
Windows下打开文件,如果不用 ios::binary,则
读取文件时,所有的 ‘\r\n’会被当做一个字符’\n’处理,即少读了一个字符’\r’
写入文件时,写入单独的’\n’时,系统自动在前面加一个’\r’,即多写了一个’\r’
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
