2009-07-20 78 views
3

我試圖以下列方式使用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加載文件,但我想使用迭代器和operator>>加載文件的某些部分。那可能嗎? 爲什麼上面的代碼不起作用?

+0

什麼是源說二進制數據? – NoMoreZealots 2009-07-21 16:06:07

+0

二進制數據可能是圖像或類似的東西。 – 2009-07-21 16:49:21

回答

3
  1. istream_iterator想要basic_istream作爲參數。
  2. basic_istream類中不可能超載operator>>類。
  3. 定義全局operator>>將導致編譯時與類成員operator>>衝突。
  4. 您可以專門爲basic_istream設置類型uint32_t。但是爲了專業化,你應該重寫basic_istream課程的所有功能。相反,你可以爲它定義啞類x,專門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; 
} 
0

主要的問題可能是你的意思是「二進制文件」。 ios::binary只確保istream對象不能用'\ n'替換特定於平臺的換行符。沒有其他的。這對你來說夠了嗎?

一個istream_iterator基本上只是一個奇怪的方式來調用operator>>。如果您的流中包含真正的二進制數據,那將會失敗。你的文件中有真實的二進制數據嗎?還是整數存儲爲字符串?

如果您需要讀取真正的二進制整數,您需要的是istream.read()或直接使用流緩衝區對象。

+0

我有真正的二進制數據。不是文字。主要問題是「爲什麼它不起作用」。我指出istream_iterator,我有uint32_t數據,而不是char(第二個模板參數)。 – 2009-07-20 18:23:05

+0

我是否應該重載`operator >>`使其工作? – 2009-07-20 18:24:12

0

您可以重新加載操作符>>以正確讀取整數。當然,它所要做的只是讀取()4個字節。但這就是所有其他運營商>>最終都在做的事情。

這裏是例子(沒有錯誤檢查,假設字節順序是一樣的電流編譯器使用等)

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

裁縫爲自己整數的味道(可能在時間和換擋分配讀取一個字節他們,在十六進制編輯器中查看文件如果你不知道字節順序),添加錯誤檢查,你應該能夠使用你現有的代碼。

編輯:啊,是的,確保這個陰影提供了stl操作符,讀取整數 - 可能必須從您正在使用的流中派生自己的類,並使用它來代替std :: istream & in,就這樣編譯器知道誰先檢查。

0

一種不同的方式做同阿列克謝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; 
}