ostream_iterator 用于二进制输出
ostream_iterator for Binary Output
我希望能够使用 ostream_iterator
to stream to a binary file. But the ostream_iterator
uses a FormattedOuputFunction 以便它写入 ASCII,而不是二进制:
std::ostream_iterator
is a single-pass OutputIterator that writes successive objects of type T
into the std::basic_ostream
object for which it was constructed, using 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));
有效,但您必须明确使用 ostream_iterator<char>
。
示例(为简洁起见省略):
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;
}
将0到255的256个字节写入foo.txt。
以上假定您希望将 int 的值作为 char 直接写入文件。根据您的评论,您希望将 int 值写入本机主机字节序中的 4 字节值(假设 int32_t)。我会使用辅助 class 来完成这项工作:
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。
对于仅使用 InputIterator or ForwardIterator for the input, a simple cast is sufficient. For more complex algorithms 的算法,可能需要编写专门的迭代器或使用 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
中的值是连续的可能很乏味,因此代码被劫持 来做到这一点:
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说明这个方法其实是成功的:
First element: 0
Last element: 255
Any non-consecutive elements: no
虽然没有尝试所有可能的 int
,但尝试了所有可能的 char
,并且由于任何 int
都可以由 char
的集合组成演示了 int
的任何集合都可以通过这种方式流式传输。
ostreambuf_iterator
比ostream_iterator
更合适。它的重量更轻,并且不进行格式化。它采用字符类型的模板参数,因此与大多数流兼容的唯一选择是 std::ostream_iterator< char >
.
一定要以二进制模式打开流。顺便说一句,标准流缓冲区从不以二进制模式打开。
我希望能够使用 ostream_iterator
to stream to a binary file. But the ostream_iterator
uses a FormattedOuputFunction 以便它写入 ASCII,而不是二进制:
std::ostream_iterator
is a single-pass OutputIterator that writes successive objects of typeT
into thestd::basic_ostream
object for which it was constructed, usingoperator<<
除了编写自己的迭代器之外,还有其他方法可以使用迭代器来编写二进制文件吗?
我正在尝试做的一个简化示例,但是 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));
有效,但您必须明确使用 ostream_iterator<char>
。
示例(为简洁起见省略):
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;
}
将0到255的256个字节写入foo.txt。
以上假定您希望将 int 的值作为 char 直接写入文件。根据您的评论,您希望将 int 值写入本机主机字节序中的 4 字节值(假设 int32_t)。我会使用辅助 class 来完成这项工作:
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。
对于仅使用 InputIterator or ForwardIterator for the input, a simple cast is sufficient. For more complex algorithms
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
中的值是连续的可能很乏味,因此代码被劫持
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说明这个方法其实是成功的:
First element: 0
Last element: 255
Any non-consecutive elements: no
虽然没有尝试所有可能的 int
,但尝试了所有可能的 char
,并且由于任何 int
都可以由 char
的集合组成演示了 int
的任何集合都可以通过这种方式流式传输。
ostreambuf_iterator
比ostream_iterator
更合适。它的重量更轻,并且不进行格式化。它采用字符类型的模板参数,因此与大多数流兼容的唯一选择是 std::ostream_iterator< char >
.
一定要以二进制模式打开流。顺便说一句,标准流缓冲区从不以二进制模式打开。