dados personalizados iostream
-
20-09-2019 - |
Pergunta
Eu tenho uma estrutura de dados definida como
struct myDataStruct
{
int32_t header;
int16_t data[8];
}
E eu quero pegar um fluxo de personagens e transformá -lo em um fluxo mydata. Qual classe de fluxo devo estender? Eu gostaria de criar uma classe de fluxo personalizada para que eu possa fazer coisas como
myDataStruct myData;
myDataStruct myDataArray[10];
myDataStream(ifstream("mydatafile.dat"));
myDataStream.get(myData);
myDataStream.read(myDataArray, 10);
Solução
Ao invés de myDataStream.get(myData)
, o que você faz é sobrecarga operator>>
Para o seu tipo de dados:
std::istream& operator>>(std::istream& is, myDataStruct& obj)
{
// read from is into obj
return is;
}
Se você quiser ler uma matriz, basta escrever um loop:
for( std::size_t idx=0; idx<10; ++idx )
{
myDataStruct tmp;
if( is >> tmp )
myDataArray[idx] = tmp;
else
throw "input stream broken!";
}
Usando um modelo de função, você também deve sobrecarregar o operador para matrizes no lado direito (mas isso eu nunca tentei):
template< std::size_t N >
std::istream& operator>>(std::istream& is, myDataStruct (&myDataArray)[N])
{
// use loop as above, using N instead of the 10
}
Mas não consigo decidir se isso é lindo ou desprezível.
Outras dicas
Se você estiver trabalhando com entrada não formatada, provavelmente deve ler diretamente em forma binária. Normalmente, você usaria alguma diretiva específica do compilador para criar estruturas de dados sem preenchimento e, em seguida, basta ler/gravar em um arquivo.
// Gcc
#pragma pack(1) // option 1: pragmas
struct frame {
std::uint32_t header;
std::uint16_t data[8];
} __attribute((packed)); // option 2: packed attribute
#pragma pack(0)
bool operator==( data const & lhs, data const & rhs )
{
bool result = lhs.header == rhs.header;
for ( int i = 0; i < 8; ++i )
{
result &= lhs.data[i] == rhs.data[i];
}
return result;
}
int main()
{
frame data = { 10, 1, 2, 3, 4, 5, 6, 7, 8 };
std::ofstream out( "data.bin", ofstream::binary );
out.write( reinterpret_cast<char*>(&data), sizeof(data) );
out.close();
std::ifstream in( "data.bin", ifstream::binary );
frame readed;
in.read( reinterpret_cast<char*>(&readed), sizeof(readed) );
in.close();
std::cout << (readed == data) << std::endl; // 1
}
A diretiva do compilador para desativar o preenchimento para o VS pode ser diferente (acredito que a diretiva Pragma trabalha no GCC e no VS, mas sempre usei o atributo).