iostream dati personalizzati
-
20-09-2019 - |
Domanda
Ho una struttura di dati definita come
struct myDataStruct
{
int32_t header;
int16_t data[8];
}
e voglio prendere un flusso di caratteri e di trasformarlo in un flusso myData. Che classe di flusso dovrei prolungare? Vorrei creare una classe di flusso personalizzato in modo che io possa fare le cose come
myDataStruct myData;
myDataStruct myDataArray[10];
myDataStream(ifstream("mydatafile.dat"));
myDataStream.get(myData);
myDataStream.read(myDataArray, 10);
Soluzione
Al posto di myDataStream.get(myData)
, quello che fai è sovraccarico operator>>
per il tipo di dati:
std::istream& operator>>(std::istream& is, myDataStruct& obj)
{
// read from is into obj
return is;
}
Se si desidera leggere in un array, basta scrivere un ciclo:
for( std::size_t idx=0; idx<10; ++idx )
{
myDataStruct tmp;
if( is >> tmp )
myDataArray[idx] = tmp;
else
throw "input stream broken!";
}
Utilizzando un modello di funzione, si dovrebbe anche in grado di sovraccaricare l'operatore per gli array sul lato destro (ma questo non ho mai provato):
template< std::size_t N >
std::istream& operator>>(std::istream& is, myDataStruct (&myDataArray)[N])
{
// use loop as above, using N instead of the 10
}
Ma io non riesco a decidere se questo è stupendo e spregevole.
Altri suggerimenti
Se si sta lavorando con l'input non formattato, probabilmente si dovrebbe leggere direttamente in forma binaria. Di solito si usa un po 'di direttiva specifica del compilatore per creare strutture di dati senza imbottitura e poi basta lettura / scrittura da un file.
// 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
}
La direttiva del compilatore per disabilitare imbottitura per VS potrebbe essere diverso (credo che la direttiva pragma funziona sia in gcc e VS, ma ho sempre usato l'attributo).