二进制输出的ostream_iterator

时间:2015-08-17 12:44:58

标签: c++ file-io iterator fstream binaryfiles

我希望能够使用ostream_iterator流式传输到二进制文件。但ostream_iterator使用FormattedOuputFunction因此它将写入ASCII,而不是二进制:

  

std::ostream_iterator是一个单行OutputIterator,它使用T

std::basic_ostream类型的连续对象写入构造它的operator<<对象中

除了编写我自己的迭代器之外,有没有办法使用迭代器来编写二进制文件?

我尝试做的简单示例,但copy语句将ASCII写入我的二进制文件:

ofstream foo("foo.txt", ios_base::binary);
vector<int> bar = {13, 42};

copy(bar.cbegin(), bar.cend(), ostream_iterator<decltype(bar)::value_type>(foo));

3 个答案:

答案 0 :(得分:3)

ostreambuf_iteratorostream_iterator更合适。重量轻得多,没有格式化。它采用字符类型的模板参数,因此与大多数流兼容的唯一选择是std::ostream_iterator< char >

确保以二进制模式打开流。顺便说一句,标准流缓冲区永远不会以二进制模式打开。

答案 1 :(得分:1)

它有效,但您必须明确使用ostream_iterator<char>

示例(包括省略的brievety):

int main(int argc, char **argv) {
    std::vector<int> arr;

    std::ofstream fd("foo.txt", std::ios::binary | std::ios::out);

    for (int i=0; i<256; i++) arr.push_back(i);

    std::ostream_iterator<char> oi(fd);
    std::copy(arr.begin(), arr.end(), oi);
    fd.close();
    return 0;
}

将在foo.txt中为0到255写入256个字节。

上面假设您想​​直接将int的值作为char写入文件。从您的注释中,您希望将int值写为本机主机端字节序中的4字节值(假设为int32_t)。我会用辅助班来完成这项工作:

class bint {
private:
    char c[sizeof(int)];

public:
    bint(const int i) { // allows bint b = 5;
        ::memcpy(c, &i, sizeof(c));
    }
    operator int() const {  // allows : bint b = 5; int i=b => gives i=5
        int i;
        ::memcpy(&i, c, sizeof(int));
        return i;
    }
    const char *getBytes() const { // gives public read-only access to the bytes
        return c;
    }
};

std::ostream& operator <<(std::ostream& out, const bint& b) {
    out.write(b.getBytes(), sizeof(int));
    return out;
}

int main(int argc, char **argv) {
    std::vector<int> arr;

    std::ofstream fd("foo.txt", std::ios::binary | std::ios::out);

    for (int i=0; i<256; i++) arr.push_back(i);

    std::ostream_iterator<bint> oi(fd);
    std::copy(arr.begin(), arr.end(), oi);
    fd.close();
    return 0;
}

这个写入1024个字节(对于大小为4的整数),包含256个第一个整数的表示。它会自动适应其他大小的int。

答案 2 :(得分:0)

对于仅使用InputIterator or ForwardIterator作为输入的算法,简单的强制转换就足够了。对于更复杂的算法writing a wrapper,可能需要编写专用迭代器或使用Boost功能。如果算法输入与这些条件一致,那么这样的事情将起作用:

ofstream foo("foo.txt", ios_base::binary);
vector<int> bar = {13, 42};

copy(reinterpret_cast<const char*>(&*bar.cbegin()), reinterpret_cast<const char*>(&*bar.cend()), ostreambuf_iterator(foo));

显然,在将其视为可靠之前,需要进行往返认证。验证output中的值是连续的可能是单调乏味的,因此代码被劫持from here来执行此操作:

ofstream foo("foo.txt", ios::binary);
vector<int> bar(numeric_limits<unsigned char>::max() + 1);

iota(bar.begin(), bar.end(), 0);

copy(reinterpret_cast<const char*>(&*bar.data()), reinterpret_cast<const char*>(&*bar.data() + bar.size()), ostreambuf_iterator<char>(foo));
foo.close();

ifstream file_read("foo.txt", ios::binary);
vector<decltype(bar)::value_type> output(bar.size());

copy(istreambuf_iterator<char>(file_read), istreambuf_iterator<char>(), reinterpret_cast<char*>(&*output.data()));

cout << "First element: " << output.front() << "\nLast element: " << output.back() << "\nAny non-consecutive elements: " << (output.cend() == mismatch(output.cbegin(), prev(output.cend()), next(output.cbegin()), [](auto first1, auto first2) { return first1 + 1 == first2; }).second ? "no\n" : "yes\n");

output from this表明此方法实际上是成功的:

  

第一个元素:0
  最后一个元素:255
  任何非连续元素:否

虽然并非所有可能的int都被尝试过,但每个可能的char都已尝试过,并且由于任何int都可以由char s集合组成,这表明任何int的集合都可以这种方式流传。