文件流是以外存文件为输入输出对象的数据流,字符串流不是以外存文件为输入输出的对象,而以内存中用户定义的字符数组(字符串)为输入输出的对象,即将数据输出到内存中的字符数组,或者从字符数组(字符串)将数据读入。字符串流也称为内存流。
字符串流也有相应的缓冲区,开始时缓冲区是空的。如果向字符数组存入数据,随着向流插入数据,流缓冲区中的数据不断增加,待缓冲区满了(或遇换行符),一起存入字符数组。如果是从字符数组读数据,先将字符数组中的数据送到流缓冲区,然后从缓冲区中提取数据赋给有关变量。
文件流类有ifstream、ofstream和fstream,而字符串流类有istrstream(input string stream缩写), ostrstream(output string stream缩写)和strstream(string stream缩写)。向内存中的一个字符数组写数据就如同向文件写数据一样,但有几点不同:
- 输出时数据不是流向外存文件,而是流向内存中的一个存储空间。输入时从内存中的存储空间读取数据。严格意义上说,这不属于输入输出,称为读写比较合适。
- 字符串流对象关联的不是文件,而是内存中的一个字符数组,因此不需要打开和关闭文件。
- 每个文件的最后都有一个文件结束符,表示文件的结束。而字符串流所关联的字符数组中没有相应的结束标志,用户要自己指定一个特殊字符作为结束符,在向字符数组写入全部数据后要写入此字符。
字符串流类没有open成员函数,因此要在建立字符串流对象时通过给定参数来确立字符串流与字符数组的关联。
一、建立输出字符串流对象
ostrstream类表示将数据写入字符串的输出流,提供的构造函数原型为:
ostrstream::ostrstream(char *buffer, int n, int mode = ios::out);
buffer是指向字符数组首元素的指针,n为指定的流缓冲区的大小(一般选与字符数组的大小相同,也可不同),第3个参数是可选的,默认为ios::out方式。示例如下:
#include <strstream> // 注意:在某些编译器中,这个头文件可能叫做 <strstream.h>
#include <iostream>
int main() {
char buffer[50];
std::ostrstream oss(buffer, sizeof(buffer));
// std::ends 用于添加空字符并设置流的状态
oss << "Hello, " << 42 <<',' <<20.0f <<',' <<true << std::ends; // 将数据写入字符串的输出流。
std::cout << oss.str() << std::endl; // oss.str() 返回内部字符串
oss.freeze(false); // 如果需要,释放缓冲区以供进一步使用(可选)
return 0;
}
运行结果如下图:
二、建立输入字符串流对象
istrstream类表示从字符串中读取数据的输入流,提供了两个带参的构造函数,其原型为:
istrstream::istrstream(char *buffer);
istrstream::istrstream(char *buffer, int n);
buffer是指向字符数组首元素的指针,用它来初始化流对象。示例如下:
#include <strstream> // 注意:在某些编译器中,这个头文件可能叫做 <strstream.h>
#include <iostream>
using namespace std;
int main() {
const char* str = "Hello 42 20 1";
istrstream iss(str);
int num;
int num2;
char word[20];
bool flag;
iss >> word >> num >>num2 >>flag; // 读取字符串和整数
cout << "Read: " <<word <<endl;
cout <<num <<endl;
cout <<num2 <<endl;
cout <<flag <<endl;
return 0;
}
运行后结果如下图:
三、建立输入输出字符串流对象
strstream类是一个双向的字符串流,既可以读取也可以写入数据,但它没有提供输入和输出之间的严格隔离,因此可能导致混淆和错误。提供的构造函数的原型为:
strstream::strstream(char *buffer, int n, int mode);
示例代码如下:
#include <strstream> // 注意:在某些编译器中,这个头文件可能叫做 <strstream.h>
#include <iostream>
using namespace std;
int main() {
char buffer[50];
strstream ss(buffer, sizeof(buffer));
ss << "Hello " << 42; // 写入字符串和整数
cout <<ss.str() <<endl <<endl;
ss.seekg(0); // 将输出位置设置回开始处
char word[20];
int num;
ss >> word >> num; // 读取刚才写入的字符串和整数
cout <<"Read: " <<endl;
cout <<word <<endl;
cout <<num << endl;
return 0;
}
运行结果如下图:
以上三个字符串流类在头文件strstream中定义的,因此程序中在用到istrstream、ostrstream和strstream类时应包含头文件strstream。
注意是str()成员函数返回指向内部缓冲区的指针,这个缓冲区在析构时可能会被销毁,因此如果您需要长时间保留这个字符串,应该复制它。
四、排序示例
在一个字符数组中存放10个整数,以空格相间隔,要求将它们放到整型数组中,再按大小排序,然后再存放回字符数组中。代码如下:
#include <strstream>
#include <iostream>
using namespace std;
int main() {
// 定义10个整数字符
char ch[50] = "12 34 65 -23 -32 33 62 99 310 35";
// 输出ch
cout <<"original sting:" <<ch <<endl;
int size = 10;
// 定义存储数组
int nums[size];
// 定义输入流对象
istrstream iss(ch, sizeof(ch));
// 循环读取
for(int i = 0; i < size; i++){
iss >>nums[i];
}
// 显示结果
cout <<"original value:";
for(int j = 0; j < size; j++) cout <<nums[j] <<' ';
cout <<endl;
// 对数组进行排序(冒泡排序)
int temp;
for(int i = 0; i < size - 1; i++){
for(int j = i + 1; j < size; j++){
if(nums[i] > nums[j]){
temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
// 建立输出字符串流对象并与数组关联
ostrstream oss(ch, sizeof(ch));
// 循环将10个整数添加到字符数组中
for(int i = 0; i < size; i++) oss <<nums[i] <<" ";
oss <<ends; // 加入'\0'
// 排序后
cout <<"Ranking value:" <<ch <<endl;
}
运行后结果如下图:
如上所示,1)用字符串流时不需要打开和关闭文件;2)通过字符串流从字符数组读数据就如同从键盘读数组一样,可以从字符数组读入字符数据。3)用输出字符串流数组oss写数据时,是人数组的首地址开始的,因此更新了数组的原内容。
五、stringstream
由于ostrstream、istrstream和strstream类已被废弃,并且stringstream类提供了更强大和灵活的功能,现C++代码应该使用stringstream代替这些旧的流类。stringstream类允许你在同一个对象中同时进行输入和输出操作,但提供了更好的控制和错误检查。
stringstream 是 C++ 标准库中的一个类,它属于 <sstream> 头文件,并且提供了字符串与流之间的交互功能。通过使用 stringstream类可以像操作文件流(如 ifstream 和 ofstream)一样来操作字符串,这包括向字符串中插入(或提取)数据。
基本说明
- stringstream 对象可以像其他流对象一样使用,如 cout 或 cin。
- 你可以使用插入运算符(<<)向 stringstream 对象中插入数据,也可以使用提取运算符(>>)从 stringstream 对象中提取数据。
- stringstream 对象的内部存储是一个字符串,你可以通过调用 str() 成员函数来获取这个字符串。
现在通过stringstream类将“四、排序示例”重新实现,代码如下:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main(){
// 创建一个 stringstream 对象
stringstream ss;
// 将整数字符串插入到ss对象中
ss.str("12 34 65 -23 -32 33 62 99 310 35");
// 输出字符串
cout <<"original:" <<ss.str() <<endl;
// 定义长度
int size = 10;
// 提取整数
int nums[size];
for(int i = 0; i < size; i++) ss >>nums[i];
// 输出nums数组中整数
cout <<"array nums:";
for(int i = 0; i < size; i++) cout <<nums[i] <<" ";
cout <<endl;
// 冒泡排序
int temp;
for(int i = 0; i < size - 1; i++){
for(int j = i + 1; j < size; j++){
if(nums[i] > nums[j]){
temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
// 清空ss
ss.clear();
// 重新插入数据
for(int i = 0; i < size; i++) ss << nums[i] <<" ";
// 输出最新结果
cout <<"Ranking value:" <<ss.str();
return 0;
}
运行后结果如下图:
示例中我们首先是创建了一个stringstream对象ss,通过str()函数插入了字符串数据,再通过str()输出字符串数据。然后使用重载运算符“>>”对字符串中整数进行提取,存储到nums数组中。再通过冒泡排序,将nums数组进行排序。最后通过重载运算符“<<”将数组中的整数输出到对象ss中,并通过str()输出更新后的字符数据。