I have an array of double:
QVector<double> Y(count);
I need to pack it to QByteArray to send via Ethernet.
So I did it. It was not too hard:
QByteArray line;
line.clear();
line.append(QByteArray::fromRawData(reinterpret_cast<const char*>(Y.data()),
count*sizeof(double)));
I try use this code to unpack the data from QByteArray recv :
QVector<double> data((line.size())/sizeof(double));
QByteArray dou(sizeof(double),0x0);
for(int i = 0; i<data.count(); i++){
dou = recv.mid(i*sizeof(double),sizeof(double));
data[i] = *reinterpret_cast<const double*>(dou.data());
dou.clear();
}
But I don’t like it. I want to find out elegant way to unpack from QByteArray to QVector<double>
Can you help me?
you can use a QDataStream which will encode the data in binary in a specific format. (more specifically first the number of items (int32) and then each item)
QVector has overloads for the stream operators
QByteArray line;
QDataStream stream(&line, QIODevice::WriteOnly);
stream << y;
and to read:
QVector<double> data;
QDataStream stream(line);
stream >> data;
The common practice is to serialize the data as a text. This will make your server and client portable. Sending a binary data over the network is not a good idea. You can create your own text protocol, or use the existing one (like Google Protocol Buffers).
Related
I have a QString containing a special character (µ) encoded in UTF-8:
QString data = "197,45 \xc2\xb5m";
I need to send that string via a Linux pipe to another program. I tried to convert the string into something like this:
char msg[15];
for(int i = 0; i < data.length(); i++) {
msg[i] = data.toUtf8()[i];
}
msg[data.length()] = '\0';
I send msg to the pipe, but I only receive "197,45 µ", not "197,45 µm". I try to read the data on the read end with:
char data[15];
read(fd, data, nbytes);
I don't know much about character/string conversion, so I would be glad if you could explain how I should approach this problem. Thank you.
What you are doing seems to be mainly "serializing the data" into a binary pipe, so an option that could make sense is to use a QDataStream which is designed for that purpose.
Something like:
QByteArray buffer;
QDataStream stream(&buffer, QIODevice::WriteOnly);
QString data = "197,45 \xc2\xb5m";
stream << data;
sendToPipe(buffer.constData(), buffer.size());
And the similar on the other side, using operator>> to read the data from the stream.
QByteArray buffer(dataPtr, size);
QDataStream stream(buffer);
QString data;
stream >> data;
It is conceptually wrong to store UTF-8 encoded bytes in a QString. Use QByteArray for that, OR use QString::fromUtf8() to convert your UTF-8 string literals to a proper QString. To go back, use the qUtf8Printable macro or QString::toUtf8 to get a QByteArray.
if you look in the documentation of QT. You can use readBytes or readRawBytes to read the binary data from a file. I am comfortable in any case, either reading the data from file or stream.
In case of readBytes - Reads the buffer s from the stream and returns a reference to the stream.
In case of readRawBytes - Reads L (length) bytes from the stream into s(buffer char*) and returns the number of bytes reads.
void readBinary(QString path)
{
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "Could not open bin file for reading";
return;
}
QDataStream in(&file);
char *data = new char[30];
qint32 bytes = in.readRawData(data, 30);
//in >> data;
qInfo() << "bytes read: " << bytes;
qInfo() << data;
file.close();
}
It shows no of bytes reads but not showing binary data on a screen.
What I am missing here?
Do we need to do serialization/de-serialization of binary data? In other words marshelling/un-marshelling of data. because I have read in official documentation encoding/decoding you need to take care of by own and need to set version of QT while reading/writing the data in the file.
How do we write back to the file/stream.
If we have another method to read/write the data directly from a file.
Do we need to write the whole binary data into buffer and then reads it again? This way we can maintain format of data.
Want some answers from you guys!
for your reference - consider the snippet of binary data in the file as mentioned below.
00000000: 0000 0520 a52a 0108 8520 0108 9320 0108 ... .*... ... ..
00000010: 9920 0108 9f20 0108 a520 0108 0000 0000 . ... ... ......
Links which I had followed on StackOverflow to resolve this issue are- Link1 , Link2, Link3, Link4
What I am missing here?
You are using raw pointers instead of QByteArray. And then you are trying to print binary data as a text.
...
QDataStream in(&file);
// You can use QByteArray which was created especially ti avoid raw char pointers
QByteArray ba(30, 0);
qint32 bytes = in.readRawData(ba.data(), ba.size());
qInfo() << "bytes read: " << bytes;
qInfo() << ba.toHex('\s'); // You read binary data, not a text. Do not try to print it as a text
Do we need to do serialization/de-serialization of binary data? In other words marshelling/un-marshelling of data. because I have read in official documentation encoding/decoding you need to take care of by own and need to set version of QT while reading/writing the data in the file.
Generally speaking, yes. Anyway you will have some serialization/de-serialization mechanism in your code. Qt suggest the mechanism out-of-the-box. You can forget about raw pointers, sizes, byte orders.
From the docs:
You don't have to set a version if you are using the current version
of Qt, but for your own custom binary formats we recommend that you
do; see Versioning in the Detailed Description.
QByteArray ba;
// fill it by some data
// Write to file
QDataStream out(&file); // output file, socket, etc.
out << ba;
// Read from file
QDataStream in(&file);
in >> ba;
How do we write back to the file/stream.
// Write to file
QDataStream out(&file); // output file, socket, etc.
out << ba;
If we have another method to read/write the data directly from a file.
Do we need to write the whole binary data into buffer and then reads it again? This way we can maintain format of data. Want some answers from you guys!
With QDataStream you can read/write directly the data structures you need, for example:
struct MyStruct
{
double d;
int a;
QString str;
QPixmap pix;
QVector<int> vec;
//overload the operators
friend QDataStream &operator << (QDataStream &out, const MyStruct &d)
{
out << d.d << d.a << d.str << d.pix << d.vec;
return out;
}
friend QDataStream &operator >> (QDataStream &in, MyStruct &d)
{
in >> d.d >> d.a >> d.str >> d.pix >> d.vec;
return in;
}
}
// Now you can:
MyStruct data;
out << data;
I have to populate a QByteArray with different data. So I'm using the QDataStream.
QByteArray buffer;
QDataStream stream(&buffer, QIODevice::WriteOnly);
qint8 dataHex= 0x04;
qint8 dataChar = 'V';
stream << dataHex<< dataChar;
qDebug() << buffer.toHex(); // "0456" This is what I want
However, I would also like to append a QByteArray to the buffer.
QByteArray buffer;
QDataStream stream(&buffer, QIODevice::WriteOnly);
qint8 dataHex= 0x04;
qint8 dataChar = 'V';
QByteArray moreData = QByteArray::fromHex("ff");
stream << dataHex<< dataChar << moreData.data(); // char * QByteArray::data ()
qDebug() << buffer.toHex(); // "045600000002ff00" I would like "0456ff"
What am I missing?
when a char* is appended it assumes \0 termination and serializes with writeBytes which also writes out the size first (as uint32)
writeBytes' doc:
Writes the length specifier len and the buffer s to the stream and
returns a reference to the stream.
The len is serialized as a quint32, followed by len bytes from s. Note
that the data is not encoded.
you can use writeRawData to circumvent it:
stream << dataHex<< dataChar;
stream.writeRawData(moreData.data(), moreDate.size());
The 00000002 is the size of the char array, which is written to the stream.
What you are missing is, QDataStream is not raw data. It has its own simple serialization format. It is most suitable for use cases where data is both written (serialized) and read back (deserialized) with QDataStream, and using a reliable QIODevice (QBuffer or QFile for example).
If you want to add raw data to a QBuffer, you could use a suitable overload of write method. But then you might as well just append to the QByteArray directly.
I am a beginner with C++ and Qt. The data sent is a string of ASCII characters ex:"jdlsfjffjf: XX" where I would like to extract the number XX. I know I should possibly use indexof to point to it but not sure how. Any direction? Here's the server side code that receives, displays and writes. I get the correct numbers in the application but gibberish characters in the file I'm writing to.
void Receiver::processPendingDatagrams()
{
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram; //array of bytes
datagram.resize(udpSocket->pendingDatagramSize()); //size it depending on sent data
udpSocket->readDatagram(datagram.data(), datagram.size()); //read all
statusLabel->setText(tr("%1 C").arg(datagram.data()));
//writing stream to file
bool ok;
QFile file("file.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out << datagram.toInt(&ok, 10 );
}
int num = datagram.right(datagram.size() - datagram.indexOf(':') - 1).toInt();
I would like to send/recieve image files and 2 ints as messages in a client server program.
I'm using QLocalSocket and QImage for this.
However I don't know how to read from the socket only after the image and the integers are fully written to the buffer, since the readyRead signal is already fired after the first couple of bytes.
Here's parts of my code:
// sending
QDataStream stream(socket);
stream << image << i << j;
// recieving
void MainWindow::readyRead() {
// ...
if (socket->bytesAvailable() > 400)
{
QByteArray b = socket->readAll();
QDataStream stream(&b, QIODevice::ReadOnly);
QImage image;
int i, j;
stream >> image >> i >> j;
// ...
}
}
I tried guessing the incoming file size, but since QImage is serialized to PNG the data size is variable and sometimes the end of the file doesn't get written to the buffer before I start to read it.
Is there an easy solution to this?
I would send a fixed size header first that describes the data being sent, specifically the type and size in bytes.
Then as you receive readReady events you pull whatever data is available into a buffer. Once you determine you have received all of the necessary data, you can stream it into a QImage object.
The BMP format has size information and PNG format has size information for each chunk. These are formats with what QImage serializes.
If you don't want to extract the information from raw data then serialize QImage first to QBuffer (so you know/control size and format better). Then stream that size and buffer.
Code example:
QBuffer buffer;
image.save(&buffer, "PNG", 100); //can change the compression level to suit the application - see http://qt-project.org/doc/qt-4.8/qimage.html#save
qint64 length = sizeof(quint32) + buffer.data().size(); //http://doc.qt.digia.com/4.7/datastreamformat.html
stream << length;
stream << buffer.data();
Then on the other end, first stream out the qint64 length so you know how big socket->bytesAvailable() has to be to stream out the full QByteArray. Then:
QByteArray ba;
stream >> ba;
QImage image = QImage::fromData(ba); // Get image from buffer data