2009-03-02 15 views
8

Desidero leggere i byte non firmati da un file binario. Così ho scritto il seguente codice.C++ lettura di caratteri non firmati dal flusso di file

#include <iostream> 
#include <fstream> 
#include <vector> 
#include <istream> 

std::string filename("file"); 
size_t bytesAvailable = 128; 
size_t toRead = 128; 

std::basic_ifstream<unsigned char> inf(filename.c_str(), std::ios_base::in | std::ios_base::binary) ; 
if (inF.good()) 
{ 
    std::vector<unsigned char> mDataBuffer; 
    mDataBuffer.resize(bytesAvailable) ; 
    inF.read(&mDataBuffer[0], toRead) ; 
    size_t counted = inF.gcount() ; 
} 

Questo risulta in lettura sempre a 0 byte come mostrato dalla variabile conteggiata.

Sembra che ci siano riferimenti sul web che dicono che ho bisogno di impostare le impostazioni locali per farlo funzionare. Come farlo esattamente non è chiaro per me.

Lo stesso codice funziona utilizzando il tipo di dati 'char' invece di 'unsigned char'

Il codice di cui sopra usando unsigned char sembra funzionare su Windows, ma fallisce in esecuzione in un coLinux Fedora 2.6.22.18.

Cosa devo fare per farlo funzionare per Linux?

+0

Non una risposta alla domanda, ma correlati.Ricorda che la definizione della classe string in C++ è 'typedef basic_string string;', quindi puoi sempre creare una classe di stringa di char unsigned a 'typedef basic_string bytestring;'. –

+0

true, ma voglio leggere un file BINARY – David

+0

.read() e .write() possono essere utilizzati per binario/testo, gli operatori di streaming << and >> sono solo per file di testo. Tutti i dati su un computer sono in ultima analisi binari, è come si sceglie di interpretarlo. – sfossen

risposta

15

C++ richiede l'attuazione solo per fornire specializzazioni esplicite per due versioni di tratti caratteriali:

std::char_traits<char> 
std::char_traits<wchar_t> 

I flussi e le stringhe usano quei tratti di capire una varietà di cose, come il valore EOF, il confronto di una serie di caratteri, l'ampliamento di un carattere in un int, e cose del genere.

Se si crea un'istanza di un flusso come

std::basic_ifstream<unsigned char> 

Devi fare in modo che vi sia una corrispondente specializzazione personaggio tratto che il flusso può utilizzare e che questa specializzazione fa fare cose utili. Inoltre, i flussi utilizzano le faccette per eseguire la formattazione e la lettura dei numeri. Allo stesso modo, devi fornire le specializzazioni anche manualmente. Lo standard non richiede nemmeno che l'implementazione abbia una definizione completa del modello primario. Così si potrebbe partecipavano ottiene un errore di compilazione:

error: specialization std::char_traits could not be instantiated.

userei ifstream invece (che è un basic_ifstream<char>) e poi andare a leggere in un vector<char>. Quando si interpretano i dati nel vettore, è ancora possibile convertirli in unsigned char in seguito.

+3

Non ho ricevuto un errore del compilatore, nessun suggerimento nella documentazione, niente, ma un errore silenzioso e una giornata sprecata. Grazie a Bjarne Stroustrup e Dennis Ritchie. – user1358

13

Non utilizzare il basic_ifstream in quanto richiede la specializzazione.

Utilizzando un buffer statico:

linux ~ $ cat test_read.cpp 
#include <fstream> 
#include <iostream> 
#include <vector> 
#include <string> 


using namespace std; 

int main(void) 
{ 
     string filename("file"); 
     size_t bytesAvailable = 128; 

     ifstream inf(filename.c_str()); 
     if(inf) 
     { 
       unsigned char mDataBuffer[ bytesAvailable ]; 
       inf.read((char*)(&mDataBuffer[0]), bytesAvailable) ; 
       size_t counted = inf.gcount(); 
       cout << counted << endl; 
     } 

     return 0; 
} 
linux ~ $ g++ test_read.cpp 
linux ~ $ echo "123456" > file 
linux ~ $ ./a.out 
7 

utilizzando un vettore:

linux ~ $ cat test_read.cpp 

#include <fstream> 
#include <iostream> 
#include <vector> 
#include <string> 


using namespace std; 

int main(void) 
{ 
     string filename("file"); 
     size_t bytesAvailable = 128; 
     size_t toRead = 128; 

     ifstream inf(filename.c_str()); 
     if(inf) 
     { 

       vector<unsigned char> mDataBuffer; 
       mDataBuffer.resize(bytesAvailable) ; 

       inf.read((char*)(&mDataBuffer[0]), toRead) ; 
       size_t counted = inf.gcount(); 
       cout << counted << " size=" << mDataBuffer.size() << endl; 
       mDataBuffer.resize(counted) ; 
       cout << counted << " size=" << mDataBuffer.size() << endl; 

     } 

     return 0; 
} 
linux ~ $ g++ test_read.cpp -Wall -o test_read 
linux ~ $ ./test_read 
7 size=128 
7 size=7 

con riserva, invece di ridimensionare in prima convocazione:

linux ~ $ cat test_read.cpp 

#include <fstream> 
#include <iostream> 
#include <vector> 
#include <string> 


using namespace std; 

int main(void) 
{ 
     string filename("file"); 
     size_t bytesAvailable = 128; 
     size_t toRead = 128; 

     ifstream inf(filename.c_str()); 
     if(inf) 
     { 

       vector<unsigned char> mDataBuffer; 
       mDataBuffer.reserve(bytesAvailable) ; 

       inf.read((char*)(&mDataBuffer[0]), toRead) ; 
       size_t counted = inf.gcount(); 
       cout << counted << " size=" << mDataBuffer.size() << endl; 
       mDataBuffer.resize(counted) ; 
       cout << counted << " size=" << mDataBuffer.size() << endl; 

     } 

     return 0; 
} 
linux ~ $ g++ test_read.cpp -Wall -o test_read 
linux ~ $ ./test_read 
7 size=0 
7 size=7 

Come si può vedere, senza la chiamare a .resize (contato), la dimensione del vettore sarà errata. Tienilo a mente. si tratta di un comune utilizzare fusione vedere cppReference

+0

Questo sta leggendo i caratteri firmati. So che questo funziona. In particolare, desidero leggere i char unsigned – David

+0

cambiando il char [] in unsigned char []. – sfossen

+0

e aggiungi il cast: P – sfossen

0

Un modo molto più semplice:

#include <fstream> 
#include <vector> 

using namespace std; 


int main() 
{ 
    vector<unsigned char> bytes; 
    ifstream file1("main1.cpp", ios_base::in | ios_base::binary); 
    unsigned char ch = file1.get(); 
    while (file1.good()) 
    { 
     bytes.push_back(ch); 
     ch = file1.get(); 
    } 
    size_t size = bytes.size(); 
    return 0; 
} 
+0

Questo è molto inefficiente. Prova a eseguire benchmark con file da 1 GB, il sovraccarico delle chiamate mostrerà una grande differenza. – sfossen

+0

perché funziona, ma una chiamata alla lettura fallisce? – David

+0

Perché il file è uno char firmato !!!! Avrei dovuto vederlo. – David

Problemi correlati