C++ostringstream&ofstream c ofstream 头文件
//simple example
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
void test()
{
//ostringstream oss;
//oss.str("abc");
ostringstream oss("abc");
cout<< oss.str()<< endl;
oss<< 8 <<endl;
oss<< 3.14<< endl;
oss<< " ok ."<< endl;
cout<< oss.str()<< endl;
oss<< 8 <<" "<< 3.14<< ""<< " ok ."<< endl;
cout<< oss.str()<< endl;
}
int main(int argc, char* argv[])
{
test();
return0;
}
如果想获取格式化好的字符串,通过ostringstream::str()函数就可以返回一个string对象, 调用string::c_str()或string::data()函数就可以获得一个指向字符缓冲的char*变量.
stringstream顾名思义是字符串流,所有输入其中的非字符类型如整形变量,浮点数都将被转换成字符串。C++为什么不提供二进制流呢?我想将对象序列化后的数据放入到一个二进制流中,然后将流缓冲保存在数据库中。我发现将binary_oarchive同stringstream结合起来使用有问题,对象在内存中的原始数据中会有许多0,而0又刚好是字符串结束的标志。解决这个问题我想到两个办法,如果将对象序列化后的数据保存到一个二进制文件中,然后再将文件的所有内容保存到数据库中,但是这种方法效率应该很低;另外一种思路就是自己实现一个二进制流类,可以仿照stringstream来实现,因为涉及到底层的读写函数都在basic_streambuf对象中,因此需要实现这个类的主要成员函数,另外需要实现一个类似于basic_ostringstream的类以向外提供接口,并融入流系统中。 花了点时间研究了下ostringstream的实现(VS2008),发现事情远没有我想象的这么简单。ostringstream相关的静态结构类图如下: 往stringstream的数据类型可以分为数字和字符串两种,其中数字包括bool,int,float/double等几种。针对数字和字符串的处理流程是不一样的,数字要被转变成字符类型,而字符串则不需要转变。对数字的处理交给num_put类,比如输入一个整型变量时,相关的处理代码如下:_VIRTUAL _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest,ios_base& _Iosbase, _Elem _Fill, long _Val)const{ // put formatted long to _Destconst size_t _Buf_size = 2 * _MAX_INT_DIG;char _Buf[_Buf_size], _Fmt[6];return (_Iput(_Dest, _Iosbase, _Fill, _Buf,::sprintf_s(_Buf, _Buf_size, _Ifmt(_Fmt,"ld",_Iosbase.flags()), _Val)));} 上面的_Dest是一个用来操作basic_streambuf的迭代器,_Iosbase应该是用来指明进制的,_Fill应该是用来控制格式的,呵呵,_Val是我最能确定的,它便是要保存的变量值。用红色标注的便是将数字转变成字符的代码,转换后的字符串保存在_Buf中,_Iput将_Buf中的内容存入到_Dest迭代器封装的basic_streambuf中。而在basic_streambuf定义了这样两个函数:int_type sputc(_Elem _Ch){ // put a characterreturn (0 < _Pnavail()? _Traits::to_int_type(*_Pninc() = _Ch): overflow(_Traits::to_int_type(_Ch)));}
streamsize sputn(const _Elem *_Ptr, streamsize _Count){ // put _Count characters from array beginning at _Ptrreturn (xsputn(_Ptr, _Count));} sputc用于一次保存一个字符,sputn则可以一次保存_Count个字符,似乎由数字转换而成的字符串都一个个调用sputc来保存,而字符串则调用sputn来保存。因为通过rdbuf方法可以获取内部的basic_streambuf对象,所以也可以这样使用ostringstream了:stringbuf *pbuf;ostringstream ss;
pbuf=ss.rdbuf(); //获得basic_streambuf对象pbuf->sputn ("Sample string",13);//向其中存入字符串cout <<pbuf->str() <<endl; 另外需要注意的一点是basic_stringbuf的str函数实现代码如下:_Mystr __CLR_OR_THIS_CALL str() const{ // return string copy of character arrayif (!(_Mystate & _Constant)&& _Mysb::pptr() != 0){ // writable, make string from write buffer_Mystr _Str(_Mysb::pbase(), (_Seekhigh< _Mysb::pptr()? _Mysb::pptr() : _Seekhigh) -_Mysb::pbase());return (_Str);}else if (!(_Mystate & _Noread)&& _Mysb::gptr() != 0){ // readable, make string from read buffer_Mystr _Str(_Mysb::eback(), _Mysb::egptr() -_Mysb::eback());return (_Str);}else{ // inaccessible, return empty string_Mystr _Nul;return (_Nul);}} 正常情况下,str函数会生成一个string对象,然后将其返回,所以“sstream.str().push_back('a');”并不能改变ostringstream的内容。"sstream.str().c_str()"获得的也并不是stringstream缓冲的地址。 再分析下ofstream吧,我想看看它是如果操作二进制文件的。ofstream的结构同ostringstream是非常类似的,只不过ostringstream中的basic_stringbuf被替换成basic_filebuf而已。ofstream的使用方法如下:ofstream fout("test.dat",ios_base::binary);
int number = 30;
fout << number;
fout.write((char *)(&number),sizeof(number));
fout.close(); 我居然不知道如果想直接以二进制的方式保存数字的话只能使用ofstream的write方法,真是羞愧啊。如果使用"<<"仍然会以字符的形式保存数字,即便在构造函数中指明"ios::binary"也不行。跟进去看了看,发现保存的流程同ostringstream也是非常相似的,使用"<<"保存除了最后文件操作不同之外,前面的代码都是一样的;而write也没有什么神奇之处,它调用basic_streambuf::sputn来保存数字。受fstream启发,我发现ostringstream同样有read和write方法,可以直接保存一个内存块(其实也可以直接使用sputn和sgetn来保存内存块),但用起来却有点小小的意外。因为ostringstream以空格分隔数据单元。stringstream sstream("fu zhijie 77");
sstream >> str1; //"fu"
sstream >> str2;//"zhijie"
sstream >> num; //77 接着我做了一个测试,代码如下:int number = 30;
stringstream ss;ss << "Sample string";
ss.write((char *)(&number),sizeof(number));
string str;
ss >> str; //"Sample"
cout << str<< endl;
ss >> str;//"string..",这个字符串就要出错了
cout << str<< endl;
int num;
ss.read((char*)&num, 4);//什么也得不到,num没有被初始化
cout << num<< endl; 看下缓冲的内容发现,number确实以"1e 00 0000"的二进制方式放置在"Samplestring"的后面,第二次取"string"的时候就要出错了,因为要么取到空格处结束,要么到"0"处结束,这样"1e"就被附到"string"的后面了,所以第二次将输出"string"带一个黑三角形。我又突发灵感,我想每次使用write写数字时,先写一个空格进去不就ok了吗?结果发现空格会被当作数字的一部分,整型本来只有四个字节,这里却生生读出五个字节来,"201e 00 00 00"对应的十进制数是7712,还是得不到正确结果。处理"Samplestring"时,中间那个空格肯定要在某个地方去除的,但是我没有找到相应的代码。看来对ostringstream同时使用"<<"和write是件很危险的事情。哎,如果每个字符串前面使用一个数字记录字符串的长度就好啦~~最后感觉C++流系统给开发者留的扩展余地并不大,开发者直接使用的流均派生自istream和ostream,比如ostream的声明如下:template<class _Elem,
class _Traits>
class basic_ostream
: virtual publicbasic_ios<_Elem, _Traits>
{// control insertions into astream buffer
public:
typedef basic_ostream<_Elem,_Traits> _Myt;
typedef basic_ios<_Elem,_Traits> _Myios;
typedef basic_streambuf<_Elem,_Traits> _Mysb;
typedef ostreambuf_iterator<_Elem,_Traits> _Iter;
typedef num_put<_Elem,_Iter> _Nput;..................}这里都限定只能使用basic_streambuf了,而开发者自定义想实现自己的streambuf就不容易融入整个系统了,如果将这个类型作为模板实例化参数就好了啊;可能是为了提高效率,整个体系中很少使用虚函数,这也限制了扩展性。
更多阅读
Windows 7中清理c盘方法 c盘windows文件夹清理
装完Win7 C盘本来还有50G的空余空间,可没过多久就只剩了1、2G了,这种情况经常出现。那么究竟我们电脑的C盘里有些什么东西在作怪,怎样才能简单方便的清除它们,下面就让我们来一起看一下C盘的奥秘吧。Windows 7中清理c盘方法——工具/原
删除文件函数和文件更名函数 c语言删除文件函数
1. 删除文件函数(remove())使用函数remove(char *filename);可删除文件filename,filename可以带路径名。函数执行成功,返回0值;否则,返回-1,且错误标志errno取下列两个值之一:ENOENT(表示文件不存在)或EACCES(表示拒绝存取)。例10.15
c盘里哪些文件可以删除 c盘中哪些文件可以删除
c盘里哪些文件可以删除——简介C盘一般是系统的安装位置,时间长久之后C盘变得越来越小,系统的运行速度就会受到影响。我们可以通过一些方法删除C盘中不需要的文件,你可以自行删除,也可以利用防护优化软件清理垃圾文件。c盘里哪些文件可
C盘window文件里哪些文件可以删除,清理的 - 电脑城 - 海员联 c盘清理工具 window10
C盘window文件里哪些文件可以删除,清理的一般人们在安装系统并全部打补丁后,会给系统减肥,也就是要删除没用的文件。什么可以删除呢?1)删除不需要的驱动文件:在WINDOWSDRIVER Cachei386driver.cab文件删除,可以节省73MB的空间。2)删除备用
C盘里文件夹的用途 c盘中的windows文件夹
你知道c盘的每个文件是干什么用的吗?1. Documents and Settings 是什么文件?答案:是系统用户设置文件夹,包括各个用户的文档、收藏夹、上网浏览信息、配置文件等。注意:这里面的东西不要随便删除,这保存着所有用户的文档和账户设置,如果删