Domanda

Voglio leggere byte senza segno da un file binario. Quindi ho scritto il seguente codice.

#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() ;
}

Ciò comporta la lettura di sempre 0 byte come mostrato dalla variabile conteggiata.

Sembra che ci siano riferimenti sul web che dicono che devo impostare le impostazioni locali per farlo funzionare. Come farlo esattamente non mi è chiaro.

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

Il codice sopra usando char senza segno sembra funzionare su Windows ma non funziona su un Fedora 2.6.22.18 di Linux.

Cosa devo fare per farlo funzionare per Linux?

È stato utile?

Soluzione

Il C ++ richiede l'implementazione 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 per capire una varietà di cose, come il valore EOF, il confronto di una gamma di caratteri, l'ampliamento di un personaggio a un int e simili.

Se si crea un'istanza di uno stream come

std::basic_ifstream<unsigned char>

Devi assicurarti che ci sia una corrispondente specializzazione del tratto di carattere che il flusso può usare e che questa specializzazione faccia cose utili. Inoltre, i flussi utilizzano le sfaccettature per eseguire la formattazione e la lettura dei numeri. Allo stesso modo devi fornire le specializzazioni di quelle troppo manualmente. Lo standard non richiede nemmeno che l'implementazione abbia una definizione completa del modello primario. Quindi potresti anche ottenere un errore di compilazione:

  

errore: impossibile specializzare la specializzazione std :: char_traits.

Userei invece ifstream (che è un basic_ifstream<char>) e poi andrei a leggere in un vector<char>. Quando si interpretano i dati nel vettore, è comunque possibile convertirli in unsigned char in un secondo momento.

Altri suggerimenti

Non utilizzare basic_ifstream in quanto richiede specializzazione.

Utilizzo di 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

usando 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

utilizzando la riserva invece del ridimensionamento in prima chiamata:

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 puoi vedere, senza la chiamata a .resize (contato), la dimensione del vettore sarà errata. Per favore, tienilo a mente. è comune usare il casting vedi cppReference

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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top