C++ 使用fstream加载二进制文件

C++ 使用fstream加载二进制文件,c++,stl,file-io,filestream,fstream,C++,Stl,File Io,Filestream,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

我正试图通过以下方式使用
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;
}
#包括
#包括
#包括
#包括
使用名称空间std;
int main()
{
基本流文件(“somefile.dat”,ios::in | ios::binary);
向量缓冲区;
assign(istream_迭代器(文件),istream_迭代器());

cout主要问题可能是您所说的“二进制文件”是什么意思。
ios::binary
只确保
istream
对象不会用“\n”替换特定于平台的换行符。其他什么都没有。这对您来说够了吗


istream\u迭代器
基本上只是调用
运算符>>
的一种奇特方式。如果流中有真实的二进制数据,则会失败。文件中是否有真实的二进制数据?或者整数是否存储为字符串


如果您需要读取实二进制整数,您需要的是
istream.read()
或直接使用流缓冲区对象。

您可以重新加载运算符>>以正确读取整数。当然,它只需读取()4个字节。但所有其他运算符>>最终都会这样做

下面是一个示例(无错误检查,假设endianess与当前编译器使用的相同,等等)

为您自己的整数风格定制(可能需要一次读取一个字节并进行移位赋值,如果您不知道字节顺序,请在十六进制编辑器中查看文件),添加错误检查,您应该能够使用现有代码

编辑:啊,是的,确保这个stl操作符读取整数——可能必须从您正在使用的流派生您自己的类,并使用它而不是std::istream&in,这样编译器才知道首先检查谁


  • istream\u迭代器
    希望
    basic\u istream
    作为参数
  • basic\u istream
    类中不可能重载
    operator>
  • 定义全局
    运算符>>
    将导致编译时与类成员
    运算符>>
    冲突
  • 您可以为类型
    uint32\u t
    专门化
    basic\u istream
    。但是对于专门化,您应该重写
    basic\u istream
    类的所有函数。相反,您可以定义虚拟类
    x
    并为其专门化
    basic\u istream
    ,如下代码所示:
  • 使用名称空间std;
    结构x{};
    名称空间标准{
    模板
    类基本流:公共基本流
    {
    公众:
    显式基本流(常量wchar\u t*\u文件名,
    ios_base::openmode_模式,
    int _Prot=(int)ios_base::_Openprot):基本的_ifstream(_Filename,_Mode,_Prot){}
    基本流和操作员>>(uint32测试和数据)
    {
    读取(和数据,1);
    归还*这个;
    }
    };
    }//名称空间std
    int main()
    {
    基本istream文件(“somefile.dat”,ios::in | ios::binary);
    向量缓冲区;
    assign(istream_迭代器(文件),istream_迭代器());
    
    可以用另一种方式来做与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;
    }
    
    #包括
    #包括
    #包括
    #包括
    struct rint//这个类允许我们读取二进制文件
    {
    //CTOR和赋值op允许从uint隐式构造
    rint(){}
    rint(无符号整数v):val(v){
    rint(rint const&r):val(r.val){}
    rint&operator=(rint const&r){this->val=r.val;返回*this;}
    rint&operator=(无符号int r){this->val=r;返回*this;}
    无符号int-val;
    //从rint到uint的隐式转换
    运算符unsigned int&()
    {
    返回此->val;
    }
    运算符unsigned int const&()const
    {
    返回此->val;
    }
    };
    //将一个单位的字符读入一个指纹
    std::istream&operator>>(std::istream&is、rint&li)
    {
    is.read(重新解释铸型(&li.val),4);
    回报是;
    }
    //从一个打印中写出一个单位的字符
    
    std::ostream&operator有真正的二进制数据,而不是文本。主要问题是“为什么它不起作用”。我已经向istream_迭代器指出,我有uint32_t数据,而不是char(第二个模板参数)。是的,重载>>来读取sizeof(uint32_t)字节。根据写文件的人和方式,您可能还需要修复endianess。@Eugene,您可以发布一些示例吗?我认为运算符重载是不够的。“如果您需要读取实二进制整数,您需要的是istream.read()或直接使用流缓冲区对象。”发布的示例。确实没有自动的方法来跟踪这些注释线程,是吗?
    istream迭代器
    使用
    basic\u istream
    作为参数,所以我不能仅仅继承
    basic\u ifstream
    并重写
    操作符>
    。这正是我需要的。请注意,在专门研究
    uint32\t您实际上是专门处理一个基本类型,或者
    unsigned int
    或者(不太可能)
    unsigned long
    typedef
    不生成通过模板(或者实际上通过C++中的任何其他类型重载)区分的类型所述二进制数据的来源是什么?二进制数据可以是图像或类似的东西。
    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;
    }
    
    #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;
    }