【问题标题】:Reading a partial file stream into a string using iterators使用迭代器将部分文件流读入字符串
【发布时间】:2011-05-04 10:56:23
【问题描述】:

这是我迄今为止尝试过的,但没有成功:

std::string ReadPartial( std::ifstream& _file, int _size )
{
    std::istreambuf_iterator<char> first( _file );
    std::istreambuf_iterator<char> last( _file );
    std::advance( last, _size );
    return std::string( first, last ); 
}

我知道如何阅读整个文件。

std::string Read( std::ifstream& _file )
{
    std::istreambuf_iterator<char> first( _file );
    std::istreambuf_iterator<char> last();
    return std::string( first, last ); 
}

但这不是我想做的。我得到一个空字符串。如果我在调试器中查看第一个和最后一个,即使在 std::advance 之后,它们也会指向相同的东西。

【问题讨论】:

  • 您看到的实际结果是什么?另外,请发布您使用的真实代码。上面的代码甚至没有编译(编辑:在查尔斯修复它之前......)。
  • 好的,修复了编译错误。对不起,这是我的错。在我的脑海中打字。
  • 不用HTML,markdown效果很好。
  • 根据习惯,我在回答中将 ifstream 更改为 istream,但应该明确指出:如果您不需要文件,则将文件流作为 istream 或 ostream(或者,很少使用 iostream)传递- 特定方法(打开、关闭等)。

标签: c++ string iterator


【解决方案1】:

您想使用迭代器有什么特别的原因吗?您可以一口气读取字节:

std::string s(_size, '\0');
_file.read(&s[0], _size);

如果你真的想使用迭代器阅读,你可以这样做:

std::string ReadPartial( std::ifstream& _file, int _size )
{
    std::istreambuf_iterator<char> first( _file );
    std::istreambuf_iterator<char> last;
    std::string s;
    s.reserve(_size);
    while (_size-- && first != last) s += *first++;
    return s;
}

【讨论】:

  • 不,没必要。但是想知道有没有可能。感谢您的回答
  • file.read(&amp;s[0], size) 不可移植且不安全。 basic_string 没有向量的连续存储保证。
  • @Steve:对于什么实现来说是真的?
  • @Roger:我宁愿不知道,因为标准允许实现者随时更改它。如果要鼓励我们编写假定某种实现的代码,为什么还要抽象呢?
  • @Steve:连续存储是required for string via indexing(缺少的是对迭代器的明确保证)。 0x 保证 std::string 以所有方式连续存储。
【解决方案2】:
std::istreambuf_iterator<char> first( _file );
std::istreambuf_iterator<char> last( _file );
std::advance( last, _size );

istreambuf_iterators 是输入迭代器。一旦您最后前进,其他迭代器也会被修改。您将它们视为前向迭代器,它们具有可以复制迭代器的属性,将其前进,然后通过前进副本获得相同的序列.

对于一般情况:

template<class InIter, class Size, class OutIter>
void copy_n(InIter begin, InIter end, Size n, OutIter dest) {
  for (; begin != end && n > 0; ++begin, --n) {
    *dest++ = *begin;
  }
}

//...
std::string ReadPartial(std::istream& file, int size) {
  std::string result;
  copy_n(istreambuf_iterator<char>(file), istreambuf_iterator<char>(),
         size, back_inserter(result));
  return result;
}

但是,在这种情况下,您最好调整字符串的大小,直接使用 istream::read 到 &result[0],最后检查您是否读取了所需的字符数。

【讨论】:

  • 但是有没有办法使用迭代器做类似的事情,或者从 ifstream 中获取前向迭代器?
  • @Allen_SM:当然你可以使用迭代器,我已经包含了 copy_n。您可以为 istreams 编写一个迭代器类型,它是一个 Forward Iterator(因为 istreams 有一个 seekg 方法),但没有必要。
【解决方案3】:

这里没有可以帮助你的标准算法,但你可以使用这个:

template< class InputIterator, class OutputIterator>
OutputIterator copy_n(InputIterator from,
                      size_t n,
                      OutputIterator to)
{
    while (n)
    {
        *to = *from;
        ++from;
        ++to;
        --n;
    }
    return to;
}

这可以像这样与ReadPartial 一起使用:

std::string ReadPartial( std::ifstream& _file, int _size )
{
    std::istreambuf_iterator<char> first( _file );
    std::string result;

    copy_n(first, _size, std::back_inserter(result));
    return result; 
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-02
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 2018-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多