[英]Load binary file using fstream
我正在尝试使用fstream
以下列方式加载二进制文件:
#include <iostream>
#include <fstream>
#include <iterator>
#include <vector>
using namespace std;
int main()
{
basic_fstream<uint32_t> file( "somefile.dat", ios::in|ios::binary );
vector<uint32_t> buffer;
buffer.assign( istream_iterator<uint32_t, uint32_t>( file ), istream_iterator<uint32_t, uint32_t>() );
cout << buffer.size() << endl;
return 0;
}
但它不起作用。 在Ubuntu中,它崩溃了std::bad_cast
异常。 在MSVC ++ 2008中它只打印0。
我知道我可以使用file.read
来加载文件,但我想使用iterator和operator>>
来加载文件的一部分。 那可能吗? 为什么上面的代码不起作用?
istream_iterator
想要basic_istream
作为参数。 basic_istream
类中重载operator>>
是不可能的。 operator>>
将导致与类成员operator>>
编译时冲突。 uint32_t
专门化basic_istream
。 但是对于专业化,你应该重写basic_istream
类的所有功能。 相反,你可以为它定义虚拟类x
和specialize basic_istream
,如下面的代码所示: using namespace std;
struct x {};
namespace std {
template<class traits>
class basic_istream<x, traits> : public basic_ifstream<uint32_t>
{
public:
explicit basic_istream<x, traits>(const wchar_t* _Filename,
ios_base::openmode _Mode,
int _Prot = (int)ios_base::_Openprot) : basic_ifstream<uint32_t>( _Filename, _Mode, _Prot ) {}
basic_istream<x, traits>& operator>>(uint32_t& data)
{
read(&data, 1);
return *this;
}
};
} // namespace std
int main()
{
basic_istream<x> file( "somefile.dat", ios::in|ios::binary );
vector<uint32_t> buffer;
buffer.assign( istream_iterator<uint32_t, x>( file ), istream_iterator<uint32_t, x>() );
cout << buffer.size() << endl;
return 0;
}
主要问题可能是“二进制文件”的含义。 ios::binary
仅确保istream
对象不会用'\\ n'替换特定于平台的换行符。 没有其他的。 这对你来说够了吗?
istream_iterator
基本上只是一种调用operator>>
的奇特方式。 如果您的流中有真正的二进制数据,则会失败。 你的文件中有真正的二进制数据吗? 或整数存储为字符串?
如果需要读取实际的二进制整数,您需要的是istream.read()
或直接使用流缓冲区对象。
您可以重新加载operator >>以正确读取整数。 当然它所做的只是read()4个字节。 但这就是所有其他运营商最终都在做的事情。
这是示例(没有错误检查,假设endianess与当前编译器使用的相同,等等)
std::istream& operator>>(std::istream& in, uint32_t& data)
{
in.read(&data, sizeof(data));
return in;
}
为您自己的整数风格量身定制(可能必须一次读取一个字节并转移分配它们,如果您不知道字节顺序,请在十六进制编辑器中查看文件),添加错误检查,您应该能够使用你现有的代码。
编辑:啊,是的,确保这个阴影提供了读取整数的stl运算符 - 可能必须从您正在使用的流派生自己的类,并使用它而不是std :: istream&in,这样编译器就知道要检查谁第一。
与Alexey Malistov的回答不同的方式:
#include <fstream>
#include <iterator>
#include <vector>
#include <iostream>
struct rint // this class will allow us to read binary
{
// ctors & assignment op allows implicit construction from uint
rint () {}
rint (unsigned int v) : val(v) {}
rint (rint const& r) : val(r.val) {}
rint& operator= (rint const& r) { this->val = r.val; return *this; }
rint& operator= (unsigned int r) { this->val = r; return *this; }
unsigned int val;
// implicit conversion to uint from rint
operator unsigned int& ()
{
return this->val;
}
operator unsigned int const& () const
{
return this->val;
}
};
// reads a uints worth of chars into an rint
std::istream& operator>> (std::istream& is, rint& li)
{
is.read(reinterpret_cast<char*>(&li.val), 4);
return is;
}
// writes a uints worth of chars out of an rint
std::ostream& operator<< (std::ostream& os, rint const& li)
{
os.write(reinterpret_cast<const char*>(&li.val), 4);
return os;
}
int main (int argc, char *argv[])
{
std::vector<int> V;
// make sure the file is opened binary & the istream-iterator is
// instantiated with rint; then use the usual copy semantics
std::ifstream file(argv[1], std::ios::binary | std::ios::in);
std::istream_iterator<rint> iter(file), end;
std::copy(iter, end, std::back_inserter(V));
for (int i = 0; i < V.size(); ++i)
std::cout << std::hex << "0x" << V[i] << std::endl;
// this will reverse the binary file at the uint level (on x86 with
// g++ this is 32-bits at a time)
std::ofstream of(argv[2], std::ios::binary | std::ios::out);
std::ostream_iterator<rint> oter(of);
std::copy(V.rbegin(), V.rend(), oter);
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.