如何在C++中正确获取输入/输出流的文件/流位置指针



如果我有一个std::stringstream变量,并且我在其中写入了一些std::string objects,并且我希望能够跟踪流位置指针并将其输出到屏幕上,我该如何使用tellp()然后稍后当我从流中提取时,即使用流进行输入时,我如何使用tellg()。如何在输入模式下再次打开流?此外,当我再次打开位置指针进行输入时,我应该用seekg()seekp()将其设置回0吗?

这是我的代码

std::string word;
std::stringstream ss;
while (word != "n") {
std::cout << "Enter a word, ( n to stop) : ";
std::cin >> word;
std::cin.ignore();
if (word == "n")
ss << std::endl;
else {
ss << word;
ss << " ";
}
}
std::cout << "The content in stringstream is : " << ss.str() << std::endl;
std::cout << "The StreamPositionPointer is"
<< ss.tellp();  // is this correct way of outputting streampointer
// how should I open the stream to get input from it to store it in a variable?
/* how should I switch the position pointer to a position when I use an
input/output stream like sstream with seekg(), seekp(), tellg(),tellp() */

您有了基本的想法。std::basic_stringstream允许同时使用std::basic_istream::tellg和std::asic_istream::seekg。有几个注意事项:

  1. 如果使用.str()成员函数,在临时对象中返回基础字符串的副本,则不会更改字符串流中的seekpos,因为您正在对副本进行操作
  2. 如果使用rdbuf()成员函数,它将返回一个指向底层字符串设备的指针。用设备输出将用输出内容,seekpos将前进到最后,但未设置eofbit
  3. 对于>>读取字符串流中最后一个项目的正常提取,在进一步搜索之前必须在字符串流上调用eofbitclear()集。如果在字符串流中调用tellg(),则流状态不是good,则返回-1

有了这个简短的例子,在需要的时候,练习seekg()tellg()以及clear(),应该可以提供您想要的解释。是以上链接中提供的各种示例的混合体:

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>

int main (void)
{
std::string str = "Hello, world";         /* initial string */
std::istringstream in(str);               /* initialized stringstream */
std::string word1, word2;                 /* two string variables used below */

std::cout << "string: " << in.str() << "nntellg " 
<< std::setw(2) << in.tellg() << " - reading into word1n";

in >> word1;    /* read into word1 from beginning */
std::cout << "tellg " << std::setw(2) << in.tellg() << " - after reading "" 
<< word1 << "", rewindingn";

in.seekg (0);   /* seekg beginning (rewind) */
std::cout << "tellg " << std::setw(2) << in.tellg() << " - reading into word2n";

in >> word2;    /* read into word2 from beginning */
std::cout << "tellg " << std::setw(2) << in.tellg() << " - after reading "" 
<< word2 << "", reading final wordn";

in >> word2;    /* read into word2 to end of stringstream, eofbit set */
std::cout << "tellg " << std::setw(2) << in.tellg() << " - after reading "" 
<< word2 << "", eofbit set, tellg() fails, must .clear()n";

in.clear();     /* clear required before further stringstring operations */

in.seekg (0, std::ios_base::beg);   /* reposition to beginning, 2nd form */
std::cout << "tellg " << std::setw(2) << in.tellg() << " - rdbuf() -> "" 
<< in.rdbuf() 
<< ""ntellg " << std::setw(2) << in.tellg() << " - reversing: "";

while (in.tellg() != 0) {   /* playing tell & seek back to beginning */
in.seekg (-1, std::ios_base::cur);          /* seek -1 from current */
std::cout << (char)in.get();                /* output character */
in.seekg (-1, std::ios_base::cur);          /* seek -1 from current */
}
std::cout << ""ntellg " << std::setw(2) << in.tellg() << " - all done.n";
}

样本使用/输出

$ ./bin/streambuf_seektellg
string: Hello, world
tellg  0 - reading into word1
tellg  6 - after reading "Hello,", rewinding
tellg  0 - reading into word2
tellg  6 - after reading "Hello,", reading final word
tellg -1 - after reading "world", eofbit set, tellg() fails, must .clear()
tellg  0 - rdbuf() -> "Hello, world"
tellg 12 - reversing "dlrow ,olleH"
tellg  0 - all done.

上面的示例显示了如何处理字符串中streambuf位置的操作。从简单的倒带,到使用goodbit以外的读取状态处理streambuf,以及如何使用tellg()seekg()的组合从结尾到开头迭代streambuf中的每个字符,从而有效地反转输出。


std::stringstream上使用seekp()的附加示例

对于您的评论,除了为了使用tellp()seekp()streambuf对象必须能够向其发送输出之外,没有太大区别。这意味着tellp()seekp()只与std::stringstreamstd::ostringstream相关,而与std::istringstream无关。因此,为了在上面的示例中定位写入位置,您只需要将类型更改为允许输出的两个变体之一。使用std::stringstream是可以的,例如

std::stringstream in(str);          /* stringstrem use both seek&tell (gp) */

现在,您可以使用tellp()seekp()移动get并在其中设置写入位置。例如,以下通过再次读取word1获得in中的当前读取位置,并保存in.tellg()报告的位置。然后,seekp()使用该位置来定位,以便在"Hello, "之后写入"big wide world!",例如

std::cout << ""ntellg " << std::setw(2) << in.tellg() 
<< " - seeking with seekp() - add "big wide world!"n";

in >> word1;                            /* move past "Hello," */
size_t pos = in.tellg();                /* save offset from beginning */
in.seekp (pos + 1);                     /* seekp() past "Hello, " */
in << "big wide world!";                /* replace remaining content */
std::cout << "nstring: " << in.str() << 'n';  /* output result */

对输出的更改

对上面输出的最后一行进行更改,然后添加新文本将导致:

...
tellg  0 seeking with seekp() - add "big wide world!"
string: Hello, big wide world!

seekg()/tellg()seekp()/tellp()是独立偏移

针对您的进一步评论,重要的是要理解...g()...p()成员函数提供了对streambuf对象开头偏移量的两个独立度量的访问。CCD_ 47和CCD_ 48与缓冲器中的读取位置相关联。(想想seek...get()tell...get()(相反,seekp()tellp()与缓冲器中的写入位置相关联。(想想seek...put()tell...put()(

对示例的最终输出进行额外的更改将清楚地表明这一点。仅将与/* output results */关联的行更改为:

/* output result */
std::cout << "nstring: " << in.str() << "ntellg  : " << in.tellg()
<< "ntellp  : " << in.tellp() << 'n';

对输出的更改

输出现在显示了in.tellg()in.tellp()在最终写入in之后报告的独立偏移,例如

...
string: Hello, big wide world!
tellg  : 6
tellp  : 22

其中,in.tellg()报告缓冲区中下一次读取(例如in >> word1;(将从何开始的位置,而in.tellp()报告缓冲区中将发生下一次写入的位置(例如in << " ... of code";(。添加in << " ... of code";后,用std::cout << 'n' << in.rdbuf() << 'n';从当前tellg()位置输出将导致:

big wide world! ... of code

仔细看看,如果你还有问题,请告诉我。

std::string word;
std::stringstream ss;
while (word != "n") {
std::cout << "Enter a word, ( n to stop) : ";
std::cin >> word;
std::cin.ignore();
if (word == "n")
ss << std::endl;
else {
ss << word;
ss << " ";
}
}

std::cout << "The content in stringstream is : " << ss.str() << std::endl;
std::cout << "The StreamPositionPosition is: "
<< ss.tellp() << std::endl;  // Yes this is correct, it will give you the position of the current position where you are outputting.
// how should i open the stream to get input from it to store it in a variable?
// If you want to convert it to string simply
std::string str = ss.str();
// If you know the order of the data, you can simply extract it
std::string wordOutput;
ss >> wordOutput;
/* how should I switch the position pointer to a position when I use an
input/output stream like sstream with seekg(), seekp(), tellg(),tellp() */
/*
seekg sets the position of input
tellg gets the position of input
seekp sets the position of output
tellp gets the position of output
*/
long length = s.tellp(); // gives you the length of the string stream
// If you want the first position do,
ss.seekp(0);
ss >> wordOutput;
// If you want the third last, do
ss.seekp(length - 3);
ss >> wordOutput;
// Examples for inputs
stringstream example;
example.write ("This is an apple",16);
long pos = example.tellp();
example.seekp (pos-7);
example.write (" sam",4);
// Will result in This is a sample

最新更新