CS106L(现代C++):介绍/Streams:stringstream

·  阅读 2761
CS106L(现代C++):介绍/Streams:stringstream

资源

课程网页
python to c++
c++文档
2019年的PPT

课程目标

  • 了解C++的特性,以及这些存在这些特性的原因
  • 阅读C++文档不再困难
  • 熟悉现代C++的设计哲学

Streams I

实际上Streams库是C++中比较老的库了,但从Streams开始是有必要的,因为当你一开始学习C++,你的第一个项目很可能是一个HelloWorld程序,你很可能希望使用输入和输出流。
这节课会介绍一些流的细节

主要内容

  • overview + 字符串流(stringstream)
  • state bits
  • 输入/输出流

使用流的原因

我们使用流的其中一个原因就是我们希望我们的程序能与外部的设备进行交互:当我们编写程序时,不是所有我们想使用的信息都包含在程序代码内的(self-contained)。
图里是我们经常会用到的一些外部设备:

image.png

控制台、键盘、文件这里不赘述。 这里提一下other programs:程序/进程之间传输数据,比如常用的IPC方式就是管道pipelines(注:pipelines实现的方式之一就是输入输出重定向)

网络中会用到sockets

比如说我们想要读取一个文件中的浮点数3.14,我们需要先读取这个浮点数信息的字符串表示:"3.14",再将其转换成浮点数3.14

image.png

还有字符串到对象/结构体的转换:

image.png 这里的关键就是你在将你程序内的某些变量、数据结构传输到控制台/socket之前,你需要将其转换成字符串。
这里面有两个难点:

  1. 如何从外部源中以字符串的形式读取/写入数据

    image.png

  2. 如何将字符串形式的数据转换成我们需要的类型

    image.png stream做的事情就是将第一个问题做了抽象封装,当你使用流时你不用考虑stream库到底是如何从外部设备中读取或写入数据的,你可以把stream想象成一个character buffer

image.png

当你用cout这个输出流的时候,你不需要考虑cout是如何与console进行交互的。

流的种类

每种流都是有一个输入流,一个输出流的:

image.png
输出流:向buffer中插入数据 stream <<
输入流:从buffer中提取数据 stream >>

stringstream

字符串流是没有与任何外部设备链接的流

image.png

这是件好事,因为我们现在可以只专注于类型转换是如何做的。

ostringstream

ostringstream: output string stream,输出流是你将信息写入输出流/你可以发送数据给输出流。 当我们构建一个ostringstream时,我们可以给他一个字符串用于初始化。

#include <sstream> // stringstream
#include <iostream> // cin cout

using namespace std;

int main(){
    ostringstream oss("Ito En Green Tea");
    cout << oss.str() << endl;
}
复制代码

常用的方法是str(),这个方法会获取oss中的整个数组然后将其转换成字符串

image.png

【编译指令】

g++ -std=c++17 -Wall ostringstream.cpp -o oss
复制代码

-Wall是打开警告(Warn all,但实际上不是全部警告,可以再加上-Wextra等),-o是给可执行文件一个指定的名字。
我们也可以向ostringstream中写入信息,这就是为什么他叫output字符串流。

ostringstream oss("Ito En Green Tea");
cout << oss.str() << endl;
oss << 16.9 << " Ounce";
cout << oss.str() << endl;
复制代码

考虑一下会打印的信息是什么?

image.png image.png

为什么输出是这样的?原因是当你创建一个oss对象打开一个流时,流的指针指向起始位置,之后当你向oss里写入数据时,指针从起始位置开始移动,他就会覆盖掉之前初始化的内容。
(注意这里的" Ounce"并不是string类的对象,它实际上是一个C string)

image.png

如果你希望在打开一个流时指针不是在起始位置,而是指定指针的偏移,你可以在创建流时构造函数内添加额外的参数:

  • ostringstream oss("Ito En Green Tea",ostringstream::ate): ate指at end,流打开时就会指向最后面,此时的输出为:
    (注:另一个常见的参数是:stringstream::binary,表示字符串流为二进制模式) image.png

第一节的视频只有一半,剩下的PPT里的内容我根据C++ Primer进行补充


又找到了20年的视频,我会再根据视频补充一些

istringstream

ostringstream oss("Ito En Green Tea");
oss << 16.9 << " Ounce";

istringstream iss(oss.str());
string output;
iss >> output;
cout << output << endl;
复制代码

上面的代码只会输出16.9,如果输入流中下一个字符为空白字符,输入流就会停止读取,继续读取时会跳过所有的前导空格。

image.png 考虑下面的代码:

istringstream iss("16.9 Ounces");
int amount;
string unit;
iss >> amount;
iss >> unit;
cout << amount/2 << "-" << unit << endl;
复制代码

amount的值是16,因为当流读到下一个字符是.,不可以解析成int类型时,就会停止解析。 unit的值是".9",因为当流读到下一个字符为空白字符就会停止读取。

image.png

可读也可写的字符串流

stringstream可读可写,使用方法与istringstreamostringstream类似,可以去google一下

手动调整流的位置

手动调整流位置涉及到三种接口/类:

  1. 获取当前流位置的方法:oss.tellpiss.tellg,注意输出流和输入流的方法不一样
  2. 创建流位置偏移:streamoff(n)
  3. 设置流位置:oss.seekp(pos)iss.seekg(pos)
    示例:
    ostringstream oss("Ito En Green Tea");
    oss << 16.9;
    streampos pos = oss.tellp() + streamoff(3);
    oss.seekp(pos);
    oss << "Black";
    cout << oss.str() << endl;
复制代码

输出:

image.png

另一种写法:

    ostringstream oss("Ito En Green Tea");
    oss << 16.9;
    oss.seekp(streamoff(3),stringstream::cur);
    oss << "Black";
    cout << oss.str() << endl;
复制代码

stringstream::cur表示当前流位置。

stringstream常用方法总结

  1. 参数为初始字符串的构造函数:istringstream iss("Initial");,ostringstream oss("Initial");
    构造函数运行添加“modes”来设置流位置(ate)和二进制模式(与文本模式对应)
  2. 向流buffer中插入/获取数据的操作符oss << variss >> var,注意,操作符会进行变量类型与字符串类型之间相互的转换
  3. 调整流位置的方法:
    1. 获取位置: oss.tellp()iss.tellg()
    2. 设置位置: oss.seekp(pos)iss.seekg(pos)
    3. 创建偏移: streamoff(n) 常用于相对于当前位置的偏移

流的链式<<、>>调用

image.png
>>是可以链式调用的,var1和var2的值都会被转换成字符格式,然后插入到oss的buffer中,那这种链式调用是如何做到的呢?
实际上,>><<运算符会返回stream对象本身,因此在他的返回值上可以再次调用运算符。(顺便问一下大家这个运算符大家都怎么称呼?管道运算符?移位运算符?输入输出运算符?)

TODO:stringbuffer

可以访问和修改流内部的buffer,CS106L没有讲,之后我自己补充一下。

分类:
阅读
标签:
收藏成功!
已添加到「」, 点击更改