Caricare file binario utilizzando fstream
-
18-09-2019 - |
Domanda
Sto cercando di caricare il file binario utilizzando fstream
nel seguente modo:
#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;
}
Ma non funziona. In Ubuntu si è schiantato con l'eccezione std::bad_cast
. Nel MSVC ++ 2008 si limita a stampare 0.
So che potrei usare file.read
caricare il file, ma voglio usare iteratore e operator>>
per caricare parti del file. È possibile? Perché il codice di cui sopra non funziona?
Soluzione
-
istream_iterator
vuolebasic_istream
come argomento. - E 'impossibile sovraccaricare
operator>>
all'interno della classebasic_istream
. - Definizione
operator>>
globale porterà a compilare i conflitti di tempo con membro della classeoperator>>
. - Si potrebbe specializzarsi
basic_istream
per il tipouint32_t
. Ma per la specializzazione si dovrebbe riscrivere tutti fuctionons della classebasic_istream
. Invece si potrebbe definire manichino classex
e si specializzanobasic_istream
per essa come nel codice seguente:
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;
}
Altri suggerimenti
È possibile ricaricare operatore >> leggere interi correttamente. Naturalmente tutto quello che farà è leggere () 4 byte. Ma questo è ciò che tutti gli altri operatori >> sono infine facendo comunque.
Ecco esempio (senza controllo degli errori, assumendo endianess è stessa compilatore corrente utilizza, etc)
std::istream& operator>>(std::istream& in, uint32_t& data)
{
in.read(&data, sizeof(data));
return in;
}
Tailor per la propria versione di numeri interi (potrebbe essere necessario leggere un byte alla volta e spostare assegnarle, guardare il file in editor esadecimale, se non si conosce l'ordine dei byte), aggiungere il controllo degli errori, e si dovrebbe essere grado di utilizzare il codice esistente.
EDIT: ah, e sì, assicurarsi che questo ombre previste operatore STL che legge numero intero - potrebbe essere necessario derivare la propria classe dal flusso che si sta utilizzando e l'uso che, invece di std :: istream & a, solo così compilatore sa che per controllare prima.
La questione principale è probabilmente quello che si intende per "file binario". Il ios::binary
fa in modo che l'oggetto istream
non sostituisce a capo specifiche della piattaforma di '\ n' solo. Nient'altro. è abbastanza per te?
Un istream_iterator
fondamentalmente è solo un modo elegante per invocare operator>>
. Se si dispone di dati binari reali nel tuo flusso, che avrà esito negativo. Avete reali dati binari nel file? O sono i numeri interi memorizzati come stringhe?
Se avete bisogno di leggere reali interi binari, quello che ti serve è o istream.read()
o utilizzando direttamente l'oggetto buffer di flusso.
Un modo diverso di fare la stessa risposta di 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;
}