文章目录

  • ​​1.字符串流​​
  • ​​3.istream_iterator与istreambuf_iterator​​
  • ​​(1)istream_iterator​​
  • ​​(2)istreambuf_iterator​​

1.字符串流

  • istringstream,输入字符串流,由istream派生而来,提供读string的功能
  • ostringstream,输出字符串流
  • stringstream
  • eg:P61\01.cpp
#include <iostream>
#include <sstream>

using namespace std;

int main(void)
{
string line;
string word;
// cin.getline();//参数是char*,不能是string

//使用getline方法,因为他是全局的,可以标准输入流,文件流,字符串流都行
//返回值是cin,读取到流结束时,跳出循环
while (getline(cin, line))//读取一行数据到line
{
istringstream iss(line);//构造字符串输入流对象

//相当于C中的sscanf
//字符串流iss关联了字符串line
//相当于从字符串line提取数据到word变量
while (iss >> word)//提取数据到word,这一行有多个单词
cout << word << "#";
cout << endl;
}
return 0;

}
  • 测试:

​cin.getine()​

istream& getline (char* s, streamsize n );istream& getline (char* s, streamsize n, char delim );

​std::getline()​

istream& getline (istream&  is, string& str, char delim);istream& getline (istream&& is, string& str, char delim);

istream& getline (istream& is, string& str);istream& getline (istream&& is, string& str);

跳出循环输入ctrl z(对应Linux系统是ctrl d),相当于一个EOF

(P61)io流类库:字符串流_算法

  • 其他说明
    字符串内部有一个缓冲区类stringbuf
    每一个输入,输出流类都有一个缓冲区,
    字符串流类的缓冲区就是stringbuf,这里可以提供,也可以不提供(自由分配)
  • (P61)io流类库:字符串流_数据结构_02


  • (P61)io流类库:字符串流_数据结构_03


  • (P61)io流类库:字符串流_算法_04

  • eg:P61\02.cpp
#include <iostream>
#include <sstream>

using namespace std;

//将double数据转换为字符串
string doubletostr( double val)
{
ostringstream oss;
oss << val;//输出到字符串流中,字符串流中的缓冲区就是分配空间,将val塞到这块空间了

//str()返回内部的空间里的字符串
return oss.str(); // return string copy of character array
}

//字符串转double,C语言是strtod
double strtodouble( const string &str)
{
istringstream iss(str);
double val;
iss >> val;//从字符串流iss提取数据到val,而字符串str与字符串流iss相对应,实际上是从字符串str提取数据到val
return val;
}

int main( void)
{
double val = 55. 55;

string str = doubletostr(val);
cout << str << endl;

str = "123.123";
val = strtodouble(str);
cout << val << endl;
return 0;

}
  • 测试:
  • (P61)io流类库:字符串流_数据结构_05

  • eg:P61\03.cpp
#include <iostream>
#include <sstream>

using namespace std;


int main( void)
{
//将192,168,0,100字符串转化为192.168.0.100
//sscanf相当于输入流,sprintf相当于输出流;

//字符串输入流+字符串输出流
//istringstream iss("192,168,0,100");
//int v1;
//int v2;
//int v3;
//int v4;
//char ch;
//iss>>v1>>ch>>v2>>ch>>v3>>ch>>v4;//192提取到v1,逗号,提取到ch。。。以此类推

//ch = '.';
//ostringstream oss;//内部会构造缓冲区,相当于sprintf
//oss<<v1<<ch<<v2<<ch<<v3<<ch<<v4;
//cout<<oss.str()<<endl;


//字符串输入输出流
string buf( "192,168,0,100");
stringstream ss(buf);//stringstream ss("192,168,0,100");
int v1;
int v2;
int v3;
int v4;
char ch;
ss >> v1 >> ch >> v2 >> ch >> v3 >> ch >> v4;//相当于输入流对象

ch = '.';
stringstream ss2;
ss2 << v1 << ch << v2 << ch << v3 << ch << v4;//相当于输出流对象

cout << ss2.str() << endl;

return 0;
}
  • 测试:

3.istream_iterator与istreambuf_iterator

(1)istream_iterator

假设我们要把一个文本文件拷贝到一个字符串对象中。似乎可以用一种很有道理的方法完成:

ifstream inputFile("d:\\test.plist");
string fileData((istream_iterator<char>(inputFile)), istream_iterator<char>());

很快你就会发现这种方法无法把文件中的空格拷贝到字符串中。

  • 那是因为istream_iterators使用operator<<函数来进行真的读取,而且operator<<函数在默认情况下忽略空格。

假如你想保留空格,你要的做就是覆盖默认情况。只要清除输入流的skipws标志就行了:

ifstream inputFile("d:\\test.plist"); 
inputFile.unset(ios::skipws); // 关闭inputFile的忽略空格标志
string fileData((istream_iterator<char>(inputFile)), istream_iterator<char>());

现在inputFile中的所有字符都拷贝到fileData中了。

此时,你会发现它们的拷贝速度不像你想象的那么快。

istream_iterators所依靠的operator<<函数进行的是格式化输入,这意味着,每次你调用的时候它们都必须做大量工作。它们必须建立和销毁sentry对象(为每个operator<<调用进行建立和清除活动的特殊的iostream对象),

它们必须检查可能影响它们行为的流标志(比如skipws),它们必须进行全面的读取错误检查,而且如果它们遇到问题,它们必须检查流的异常掩码来决定是否该抛出一个异常。

如果进行格式化输入,这些都是重要的活动,但如果你需要的只是从输入流中抓取下一个字符,这样做就过度了。

(2)istreambuf_iterator

你可以像istream_iterator一样使用istreambuf_iterator。

  • istreambuf_iterator对象进入流的缓冲区,并直接读取下一个字符。(更明确地说,一个istreambuf_iterator 对象从一个istream s中读取会调用s.rdbuf()->sgetc()来读s的下一个字符。)
  • 把我们的文件读取代码改为使用istreambuf_iterator相当简单:
ifstream inputFile("d:\\test.plist"); 
string fileData((istreambuf_iterator<char>(inputFile)), istreambuf_iterator<char>());

注意这里不需要“unset”skipws标志,istreambuf_iterator不忽略任何字符。

  • 它们只抓取流缓冲区的下一个字符。
  • 对于无格式的一个一个字符输入,你总是应该考虑使用istreambuf_iterator。
  • eg:
#include <iostream>
#include <fstream>
#include <streambuf>

std::ifstream file(“d:\\test.plist”);
if (!file.is_open())
{
return NULL;
}
std::string content;
content.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());

注:另外有的程序员使用 ifstream 读取文件内容,然后直接赋值给std::string对象,肯定是错误的。因为:读取的char*类型赋值给string时,默认遇到 \0 就会结束,会丢弃后面的字符。