2009-03-02 8 views
8

Quiero leer los bytes sin signo de un archivo binario. Así que escribí el siguiente código.C++ leyendo el carácter sin signo de la secuencia de archivos

#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 haber referencias en la web que dicen que necesito configurar 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 utilizando unsigned char parece funcionar en Windows pero no se ejecuta en un coLinux Fedora 2.6.22.18.

¿Qué debo hacer para que funcione en Linux?

+0

No es una respuesta a la pregunta, pero relacionado.Recuerde que la definición de la clase de cadena en C++ es 'typedef basic_string string;', por lo que siempre puede hacer una cadena de caracteres sin signo class a la 'typedef basic_string bytestring;'. –

+0

cierto, pero quiero leer un archivo BINARIO – David

+0

.read() y .write() se pueden utilizar para binario/texto, los operadores de flujo << and >> son solo para archivos de texto. Todos los datos en una computadora son en última instancia binarios, es la forma de elegir interpretarlos. – sfossen

Respuesta

15

C++ requiere la aplicación sólo para proporcionar especializaciones explícitos para dos versiones de los rasgos de carácter:

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

Las corrientes y las cadenas utilizan esos rasgos que encontrar una variedad de cosas, como el valor de EOF, la comparación de un rango de caracteres, la ampliación de un carácter a un int, y esas cosas.

Si usted instancia como una corriente

std::basic_ifstream<unsigned char> 

Usted tiene que asegurarse de que no hay una especialización correspondiente rasgo de carácter que la corriente puede utilizar y que esta especialización Qué hace cosas útiles. Además, las secuencias usan facetas para realizar el formateo y la lectura reales de los números. Del mismo modo, debe proporcionar especializaciones de esos también de forma manual. El estándar ni siquiera requiere que la implementación tenga una definición completa de la plantilla primaria. Por lo que podría aswell obtiene un error de compilación:

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

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

+3

No obtuve un error de compilación, ni indicios en la documentación, nada, pero una falla silenciosa y un día perdido. Gracias Bjarne Stroustrup y Dennis Ritchie. – user1358

13

No utilice basic_ifstream ya que requiere especialización.

El uso de un buffer 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 

utilizando 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 la reserva en lugar de cambiar el tamaño de 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 se puede ver, sin la llamar a .resize (contado), el tamaño del vector será incorrecto. Por favor tenlo en mente. es un común el uso de la fundición ver cppReference

+0

Esto está leyendo chars firmados. Sé que esto funciona Específicamente, quiero leer los caracteres sin signo – David

+0

simplemente cambie el carácter [] por el carácter sin signo []. – sfossen

+0

y agregue el molde: P – sfossen

0

Una manera 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; 
} 
+0

Eso es muy ineficiente. Intente ejecutar puntos de referencia con archivos de 1GB, la sobrecarga de las llamadas mostrará una gran diferencia. – sfossen

+0

¿por qué funciona esto pero falla una llamada de lectura? – David

+0

¡¡¡Porque el archivo es un char firmado !!!! Debería haber visto eso. – David

Cuestiones relacionadas