一、概览与类体系
C++ 提供三种基于内存字符串的流,定义在 <sstream>
中:
std::istringstream
:输入流,从已有字符串中读取并解析。std::ostringstream
:输出流,向内部缓冲区写入内容,最终取回为字符串。std::stringstream
:读写流,兼具istringstream
和ostringstream
的功能。
它们都继承自 std::basic_iostream<char>
,可使用所有流操作符与格式化工具。
二、常见用法
1. 构造与取出字符串
std::ostringstream oss; // 默认空缓冲
oss << "Value=" << 42 << ", Pi="
<< std::fixed << std::setprecision(3) << 3.14159;
// 获取结果
std::string s = oss.str(); // s == "Value=42, Pi=3.142"
str()
:获取当前缓冲区的字符串。str(const std::string&)
:重置缓冲区内容。
2. 字符串解析
std::string line = "123 45.6 OK";
// 将 line 内容作为流缓冲
std::istringstream iss(line);
int a;
double b;
std::string status;
// 按空白自动切分并转换
if (iss >> a >> b >> status) {
// a==123, b==45.6, status=="OK"
}
// 检查是否完全消费或错误
if (iss.fail() && !iss.eof()) {
// 转换中发生格式错误
}
- 运算符>> 会跳过空白,并尝试按目标类型解析。
- 解析失败时,流会置
failbit
,后续操作将不中断程序,除非打开异常模式。
3. 读写混合
std::stringstream ss;
ss << "X=" << 10 << ";Y=" << 20;
// 重设读写位置到开头
ss.seekg(0);
// 逐字符读取、跳过标识
char ch;
int x, y;
ss >> ch >> ch >> x; // 假设格式 "X=10"
ss >> ch >> ch >> y; // 跳过 ";Y="
seekg
/seekp
可重定位读/写指针,方便混合使用。- 在写完后若要读,通常要
ss.seekg(0)
;同理,由读转写可用ss.seekp(0, std::ios::end)
。
三、格式控制与状态检查
-
格式化:与标准流一致,可用
<iomanip>
中的操纵器,如std::hex
、std::setw
、std::setfill
、std::boolalpha
、std::fixed
、std::scientific
等调整输出格式。 -
状态位:用
good()
、fail()
、eof()
、bad()
、rdstate()
检测流状态;用clear()
重置。 -
异常模式:
iss.exceptions(std::ios::failbit | std::ios::badbit); try { int v; iss >> v; // 解析失败即抛异常 } catch (const std::ios_base::failure& e) { // 处理错误 }
默认不会抛。
四、性能与注意事项
- 避免频繁
str()
调用:每次str()
都会拷贝缓冲区字符串,影响性能。可在最后一次取用时再调用。 - 预分配缓冲:可用
ss.str().reserve(n)
或先构造带初始字符串的stringstream
,减少动态分配。 - 切换格式后状态保留:如果你在一个流上设置了某个格式(如
std::hex
),它会一直生效, remember to reset(std::dec
)。 - 注意空白和分隔:
>>
默认以空白分隔,解析整行或含空格的字段时要用std::getline
。 - 多语种/宽字符:对于 Unicode 或宽字符流请使用
std::basic_stringstream<wchar_t>
。
五、综合示例
#include <iostream>
#include <sstream>
#include <iomanip>
int main() {
// 构建字符串
std::ostringstream oss;
oss << "Point("
<< std::setw(2) << std::setfill('0')
<< 7 << ","
<< std::fixed << std::setprecision(1)
<< 3.14 << ")";
std::string desc = oss.str(); // "Point(07,3.1)"
std::cout << desc << "\n";
// 解析回数值
std::istringstream iss(desc);
char ch;
int ix;
double dy;
if ( (iss >> ch >> ch >> ix >> ch >> dy >> ch).good() ) {
std::cout << "Parsed: x=" << ix << ", y=" << dy << "\n";
} else {
std::cerr << "Parse error\n";
}
// 读写混合:累加偏移
std::stringstream ss("100 200 300");
int sum = 0, v;
while (ss >> v) sum += v; // sum=600
std::cout << "Sum=" << sum << "\n";
return 0;
}
小结
std::ostringstream
:安全构建复杂字符串/格式化输出。std::istringstream
:高效拆解、解析已知格式的文本。std::stringstream
:读写一体,用于需要往返操作的场景。- 始终关注流状态和格式保留,并合理管理缓冲与性能。
掌握这些知识,你就能在日志构建、文本解析、动态内容生成等场景中,灵活高效地运用 C++ 的字符串流。