1) C++ 文件I/O流结构
须include<fstream>,同时最好也include<iostream>,为了可移植性,因为fstream不一定会include<iostream>。
l ios_base基类 :public ios
定义了所有流共有的内容,不依赖于流所处理的字符类型。
l basic_ios<charT> :public ios_base
定义跟字符相关的输入输出共有的类,一般很少使用。
l basic_istream<charT> : public basic_ios<charT>
typedef basic_istream<char> istream;
typedef basic_istream<wchar_t> wistream;
istream cin;
l basic_ifstream<charT> : public basic_istream <charT>
typedef basic_ifstream<char> ifstream;
typedef basic_ifstream<wchar_t> wifstream;
l basic_ostream<charT> : public basic_ios<charT>
typedef basic_ostream<char> ostream;
typedef basic_ostream<wchar_t> wostream;
ostream cout;
ostream cerr;
cerr与cout的不同是cerr不带缓冲区,比较快。
l basic_ofstream<charT> : public basic_ostream <charT>
typedef basic_ofstream<char> ofstream;
typedef basic_ofstream<wchar_t> wofstream;
l basic_iostream<charT>
: public basic_istream<charT>,
basic_ostream<charT>
typedef basic_iostream<char> iostream;
l basic_fstream<charT> : public basic_iostream <charT>
typedef basic_fstream<char> fstream;
typedef basic_fstream<wchar_t> wfstream;
2) C++文件处理
l 文件打开模式
ios::in
可用于读取文件;防止更改或截断文件;
当用ofstream时,以这种模式打开的文件,
可往文件中间覆盖存在的内容。
ios::out
当用ifstream时,以这种模式打开也可以写入文件,参看下文。
ios::app
仅用于追加文件内容
以这个方式打开文件,无论怎么移动文件指针,都只能往文件末尾追加。
ios::ate
如果文件存在,文件指针默认为文件末尾。
当用ofstream时,以这种模式打开和trunc是一样的效果,文件内容被清空。
ios::trunc
如果文件存在,则清空文件内容
默认输出是这样方式,如果没有指定app 或in。
ios::binary
文件以二进制打开,默认为文本方式。
只在windows上存在的方式:文件系统用回车(13)/换行(10)来表示行的结束符。当写入’/n’ (10)时,系统写入回车换行符。读取时做相反处理。
而用二进制方式读写时,系统会忽略这种转换,完全按字节存取。
例子:
ios::in | ios::out | ios::binary
l 优雅的文件流缓冲 – 推荐的文件存取方式
结构定义
basic_streambuffer<charT>
basic_filebuf<charT>: public basic_streambuffer<charT>
basic_stringbuf<charT>: public basic_streambuffer<charT>
流接口
任何流对象都可以通过rdbuf()获取流缓冲
使用例子
ifstream inFile(“a.txt”);
cout<<inFile.rdbuf()<<endl; //输出文件内容
//需要重置文件指针
inFile.seekg(0,ios::beg);
ofstream outFile(“b.txt”);
outFile<<inFile.rdbuf(); //拷贝文件。
l 文件流定位
记住当前流指针
ofstream – streampos tellp()
tellp意思是tell me the put pointer
ifstream – streampos tellg()
tellg 意思是tell me the get pointer
绝对移动文件指针
利用streampos.seekpos()即可返回到指定的指针
比如,ofstream outFile(“a.txt”);
streampos pos = outFile.tellp();
pos.seekpos();
流位置定义
流的开始位置 0 – ios::beg
流的当前位置 1 – ios::cur
流的结束位置 2 – ios::end
相对移动文件指针
ofstream – seekp(字节数,方向)
字节数可正可负,注意合理性,比如指针为开始位置,字节数应为正。
ifstream – seekg(字节数,方向)
同上。
l 只能覆盖文件部分内容 – 不能往中间插入
ofstream out1("d://a.txt", ios::in);
out1.seekp(10,0);
out1.write("hello every one!",sizeof("hello every one!"));
out1.close();
l 输入输出文件
方式1
用fstream,设置ios::in|ios::out标志。
当从读变成写或从写变成读时,须重定位文件流或
刷新流(flush)
方式2
ifstream inFile(“a.txt”, ios::in|ios::out);
ostream outFile(inFile.rdbuf());
//可移动指针outFile用来写
//可移动指针inFile用来读
outFile<<”内容”;
cout<<inFile.rdbuf();
3) 字符串输入输出流
须include <sstream>
l 字符串流结构与文件流一样
basic_istringstream 替换 basic_ifstream
basic_ostringstream 替换 basic_ofstream
basic_stringstream 替换 basic_fstream
l 输入流用法
字符串转换
istringstream strStream(“345 45 1.54 hello”);
int i = 0; //345
int j = 0; //45
float k = 0; //1.54
string str; //hello
strStream >> i>>j>>k>>str;
如果改成istringstream strStream(“345s 45 1.54 hello”);
输出为:345 0 0
用这个可将小数点前后的变成整数。
类型转换
void DateInput(string& str)
{
istringstream strStream(str);
Date date;
strStream >> date;
if( strStream ) //bool返回值
{
//date正确
}
else
{
//输出错误
}
}
l 输出流用法
格式化字符串
ostringstream strStream;
int a = 10;
float b = 1.5;
string str = “yeming”;
strStream << a<<b<<str;
cout<<strStream.str();
将文件内容变成字符串
ifstream inFile(“a.txt”);
ostringstream os;
os<<inFile.rdbuf();
4) 输出流格式化1 – 函数调用
l 改变标志
fmtflags ios::flags(fmtflags newflags); //改变所有标志
fmtflags ios::setf(fmtflags mask); //可用 | 连接标志
fmtflags ios::unsetf( fmtflags mask); //清除标志
fmtflags ios::setf(fmtflags bit, fmtflags field); //请看Field标志部分
l 开/关标志
ios::skipws
跳过空格,默认输入流就是跳过空格
ios::showbae
显示基数前缀
ios::showpos
cout.setf(ios::showpos)显示数字正负号
ios::unitbuf
cout.set(ios::unitbuf) 使得每次输出后都刷新缓冲区到文件中
cout<<”hello”;
cout<<”yeming”;
cerr就是把这个标志打开了,所以如果错误输出太多,会影响效率。
ios::showuppercase
输出十六进制时A…F是大写,科学计算为E
ios::showpoint
显示浮点数时,会在后面显示0
比如cout<<0.234f; //显示0.234000
l Field标志
ios::basefield
- ios::dec //使整数为10进制,没有前缀
- ios::hex //16进制,0x
- ios::oct //8进制,0
cout.setf(ios::hex, ios::basefield);
ios::adjustfield
- ios::left //数字左对齐,用字符填充右边空位
- ios::right //数字右对齐,用字符填充左边空位,默认方式
- ios::internal //字符填充于正负号或基数符号的后面
cout.setf(ios::internal, ios::adjustfield);
+0000124; //而不是0000+124
ios::floatfield
- ios::scientific //以科学技术显示浮点数(带e的写法)
- ios::fixed //以固定格式显示浮点数
cout.setf(ios::scientific, ios::floatfield);
l 位宽、填充字符、精度设置
位宽
cout.width(); //返回当前宽度,默认为0 (生成能容纳数字的最小宽度)
cout.width(int n); //设置宽度并返回之前的宽度
如果设置为10,显示时,不足则补填充字符,包括符号位和基数;
如果超过10,则正常显示不会截断。
每次输出>>后都得重新设置宽度,否则默认为0。
填充字符
fill(); //返回当前填充符,默认为空格
fill(int n); //设置并返回之前的填充符
精度
precision(); //返回当前的精度,默认为小数点后6位
precision(int n); //设置并返回之前的精度
5) 输出流格式化2 – 操纵算子
用户实现跟前面一样的功能,只不过不通过显式的函数调用。
一直管用,直到有人显式的更改它。
比如,cout<<showpos<<132<<endl;
l 无参数算子 <iostream>
showbase
noshowbase
showpos
noshowpos
uppercase
nouppercase
showpoint
noshowpoint
skipws // cin<<ws
noskipws
left
right
internal
scientific
fixed
endl //换行,且刷新缓冲区
flush //刷新缓冲区
重载算子
ostream& endl(ostream& os)
{
return os << “/r/n”;
//对于endl算子,足够了,可以给别的算子加更多的逻辑
}
ostream& ostream::operator << (ostream& (*pf)(ostream&))
{
return pf(*this);
}
l 有参数算子 <iomanip>
用法: cout<<setfill(10)<<133<<endl;
setiosflags(fmtflags n) //相当于setf
resetiosflags(fmtflags n) //相当于unsetf
setbase(int n)
setfill(char n)
setprecision(int n)
setw(int n) //宽度,用于输入流时,只对字符串有意义。
重载算子 – 二进制输出
class Binary
{
private:
unsigned long m_number;
public:
Binary(unsigned long nNumber){ m_number = nNumber;}
friend ostream& operator << (ostream& os, const Binary& b)
{
const unsigned long MAX = numeric_limits<unsigned long>::max();
unsigned long bit = ~(MAX >> 1);
while(bit)
{
os<<(b.n & bit ? ‘1’:’0’);
bit >>=1;
}
return os;
}
};
ostringstream str;
str<<Binary(23444);
cout<<str.str()<<endl;
6) 国际化
l 宽字符
有时候一个函数处理char,需要一个函数去处理;而处理wchar_t,又需要另外一个函数去处理(C不允许函数重载)。
可以用char_traits来解决,比如:
template<class charT, class traits>
std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT, traits>& os, const Data& date)
{
//实现
}
l 区域Locale <locale>
更换区域
默认的区域名为C,为英美地区使用。
可以针对输入输出换区域:
locale loc;
cout<<loc.name<<endl; //C
locale cur = cout.getloc();
cout.imbue(locale(“french”)); //换法国区域
cin.imbue(cur);//比如,输入数字可能以,或.分割
也可以使用这样的方式分割数字:
#include <locale>
class thousands_sep_facet:public numpunct<char>
{
public:
explicit thousands_sep_facet( size_t r=0 ) : numpunct<char>(r)
{
}
protected:
string do_grouping() const
{
return "/003";
}
};
locale loc( locale(), new thousands_sep_facet );
cout.imbue( loc );
cout<<10000000<<endl; //10,000,000
区域分类
collate
按照不同的字符顺序比较字符串
ctype
对字符类型抽象
monetary
货币表示
local loc(“french”);
string symbol = use_facet<moneypunct<char> >(loc).curr_symbol();
cout<<symbol<<123<<endl;
numeric
数字显示
time
时间显示
messages
不同语言下的错误显示