代码之家  ›  专栏  ›  技术社区  ›  Kirill V. Lyadvinsky

使用fstream加载二进制文件

  •  3
  • Kirill V. Lyadvinsky  · 技术社区  · 16 年前

    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

    我知道我可以用 file.read operator>> 为什么

    4 回复  |  直到 16 年前
        1
  •  3
  •   Alexey Malistov    16 年前
    1. istream_iterator 想要 basic_istream 作为论据。
    2. 超载是不可能的 operator>> 内部 基本流 类。
    3. 定义全局 操作员>> 将导致编译时与类成员发生冲突 操作员>> .
    4. 你可以专攻 基本流 对于类型 uint32_t 。但对于专业化,你应该重写所有函数 基本流 类。相反,您可以定义虚拟类 x 并专攻 基本流 如以下代码所示:
    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;
    }
    
        2
  •  0
  •   Eugene    16 年前

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

    这是一个示例(假设endianes与当前编译器使用的相同,则不进行错误检查等)

    std::istream& operator>>(std::istream& in, uint32_t& data)
    {
        in.read(&data, sizeof(data));
        return in;
    }
    

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

    EDIT:啊,是的,确保这个shadows提供了读取整数的stl运算符——可能必须从您正在使用的流中派生自己的类,并使用它来代替std::istream&在中,这样编译器就知道该先检查谁。

        3
  •  0
  •   sbi    16 年前

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

    istream_iterator 基本上只是一种花哨的调用方式 operator>> 。如果你的流中有真正的二进制数据,那将失败。你的文件中有真正的二进制数据吗?还是整数存储为字符串?

    如果你需要读取实数二进制整数,你需要的是 istream.read()

        4
  •  0
  •   thechao    15 年前

    与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;
    }