使用std :: ostream_iterator写入二进制文件

时间:2015-06-30 07:16:22

标签: c++ stream iterator

考虑以下代码:

std::vector<long> d(3);
d[0] = 0;
d[1] = 1;
d[2] = 2;

std::ofstream f("d:/ofstream.txt", std::ios_base::binary);
std::ostream_iterator<long> out(f);

std::copy(std::begin(d), std::end(d), out);

生成的文件大小为3个字节,因此写为char,而不是long。在这种情况下我可以使用std::ostream_iterator吗?

我无法理解它的行为。

1 个答案:

答案 0 :(得分:4)

std::stream_iterator使用“普通” operator<<语义,它是格式化输出(非二进制)

来自cppreference;

  

std::ostream_iterator是一个单行OutputIterator,它使用T将类型为std::basic_ostream的连续对象写入构造它的operator<<对象中。每次写入操作后,可选的分隔符字符串将写入输出流。当迭代器(无论是否取消引用)被分配时,执行写操作。增加std::ostream_iterator是无操作。

您可以实现一个自定义迭代器,将未格式化的输出写入流;它将被要求遵循与std::stream_iterator w.r.t相同的约束。迭代器要求,特别是

  

operator=将对象写入关联的输出序列

在这种情况下,应将对象作为无格式数据(原始二进制内容)写入流中。您的确切实现可能会有所不同,但在这里我们使用简单的二进制转储进行演示。

#include <iostream>
#include <algorithm>
#include <utility>
#include <iterator>

using namespace std;

template <class T, class CharT = char, class Traits = std::char_traits<CharT>>
class ostreambin_iterator :
    public std::iterator<std::output_iterator_tag, void, void, void, void> {
public:
    typedef std::basic_ostream<CharT, Traits> ostream_type;
    typedef Traits traits_type;
    typedef CharT  char_type;

    ostreambin_iterator(ostream_type& stream) : stream_(stream) { }

    ostreambin_iterator& operator=(T const& value) 
    {
        // basic implementation for demonstration
        stream_.write(reinterpret_cast<const char*>(&value), sizeof(T));
        return *this;
    }

    ostreambin_iterator& operator*()     { return *this; }
    ostreambin_iterator& operator++()    { return *this; }
    ostreambin_iterator& operator++(int) { return *this; }

protected:
    ostream_type& stream_;
};

int main() {
    std::vector<long> d(3);
    d[0] = 0x303030; // test some width past a single byte
    d[1] = 0x31;
    d[2] = 0x32;

    ostreambin_iterator<long> out(cout);

    cout << "begin" << endl;
    copy(std::begin(d), std::end(d), out);
    cout << endl;
    cout << "end" << endl;
}

Live demo

我已将cout用于演示(因此您的控制台上可能无法显示NULL字节。)