C ++ lectura de caracteres sin firmar de la secuencia de archivos
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?
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;
}