Pregunta

Quiero leer bytes sin firmar de un archivo binario. Entonces escribí el siguiente código.

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

Esto resulta en la lectura en siempre 0 bytes como se muestra por la variable contada.

Parece que hay referencias en la web que dicen que necesito establecer la configuración regional para que esto funcione. Cómo hacer esto exactamente no está claro para mí.

El mismo código funciona utilizando el tipo de datos 'char' en lugar de 'unsigned char'

El código anterior que usa char sin firmar parece funcionar en Windows pero falla al ejecutarse en un colinux Fedora 2.6.22.18.

¿Qué necesito hacer para que funcione en Linux?

¿Fue útil?

Solución

C ++ requiere la implementación solo para proporcionar especializaciones explícitas para dos versiones de rasgos de caracteres:

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

Las secuencias y cadenas utilizan esos rasgos para descubrir una variedad de cosas, como el valor EOF, la comparación de un rango de caracteres, el ensanchamiento de un carácter a un int, y esas cosas.

Si crea una instancia de una secuencia como

std::basic_ifstream<unsigned char>

Debe asegurarse de que haya una especialización de rasgo de carácter correspondiente que la secuencia pueda usar y que esta especialización haga cosas útiles. Además, las transmisiones usan facetas para formatear y leer los números. Del mismo modo, debe proporcionar especializaciones de esos demasiado manualmente. El estándar ni siquiera requiere que la implementación tenga una definición completa de la plantilla primaria. Entonces también podría obtener un error de compilación:

  

error: no se pudo instanciar la especialización std :: char_traits.

En su lugar, usaría ifstream (que es un basic_ifstream<char>) y luego iría y leería un vector<char>. Al interpretar los datos en el vector, aún puede convertirlos a unsigned char más tarde.

Otros consejos

No utilice basic_ifstream ya que requiere especialización.

Uso de un búfer estático:

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 vector:

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

usando reserve en lugar de redimensionar en la primera llamada:

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

Como puede ver, sin la llamada a .resize (contado), el tamaño del vector será incorrecto. Por favor tenlo en mente. es común usar casting ver cppReference

Una forma mucho más fácil:

#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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top