QByteArray byteArray;
QDataStream dataStream(&byteArray, QIODevice::WriteOnly);
dataStream << (quint8)22;
dataStream << "test2";
qInfo() << byteArray;
Result: \x16\x00\x00\x00\x06test2\x00
Why is it using 4 bytes instead of 1? I explicitly say that I want it to be unsigned char. Is there some memory aligning behind the scenes? Can I turn it off?
EDIT: It seems to happen only when I write char* it adds 3 bytes on the beginning from nowhere.
\x16\x00\x00\x00\x06test2\x00
\x16 is you uint8.
\x00\x00\x00\x06 is a fixed size, four byte header of the string length (apparently including the null).
Then your string, followed by a terminating null.
Related
i have byte image array i want to write this byte array to another byte array with add some another value on second byte array , i'm using this code but i think something is wrong
QByteArray byteArray;
QDataStream ds(&byteArray,QIODevice::ReadWrite);
ds<<(qint32)20;
ds<<bArray;
qint32 code;
ds>>code;
when i trace ds>>code it is always have 0 value but in fact it must have 20 value and i used ds.resetStatus(); but it return 0 value again
I suspect that QDataStream::operator<< functions sets some sort of pointer/iterator/index to point to the next location where they can start inserting data when the next call is made. QDataStream::operator>> probably starts to read from the same location.
QDataStream::resetStatus() does not change the position from where the object reads/writes. It merely resets the status to QDataStream::Ok to allow you to read from the stream after an error has occurred.
You can use two QDataStream objects -- one for writing to the QByteArray and the other for reading from the same QByteArray.
QByteArray byteArray;
QDataStream ds_w(&byteArray,QIODevice::WriteOnly);
QDataStream ds_r(&byteArray,QIODevice::ReadOnly);
ds_w << (qint32)20;
ds_w << bArray;
qint32 code;
ds_r >> code;
My goal is to save a QAudioRecorder recording into memory. From my research it seems the best way to store the recording is to use a QByteArray. My audio recorder is probed using a QAudioProbe.
From the audioBufferProbed signal I try to append the data to the byte array using this slot method.
QByteArray *byteArr;
void AudioRecorder::processBuffer(const QAudioBuffer &buffer)
{
byteArr->append(buffer.constData<char>());
qDebug() << buffer.byteCount();
qDebug() << byteArr->size();
}
However that doesn't seem to work considering buffer.byteCount(); returns 4092 constantly which seems normal but byteArr->size(); returns weird and irregular increments starting off usually with 2, 4, 6, 7, 189.
The data also usually only ends up being around 18kb in size which also leads me to believe that the data is not being appended into the byte array correctly.
According to the QByteArray::size() docs size() should give how many bytes are in the array. Along with QAudioBuffer::byteCount() which also should give the amount of bytes in the current buffer, shouldn't the full 4092 from the buffer be copied to the array?
I am also open to another solution that doesn't use QByteArray if there is a better way to store the data.
You have a QByteArray pointer, but have not set it to anything.
You need to set it to a QByteArray, in your case you can use QByteArray(const char * data, int size):
byteArr = new QByteArray(buffer.constData<char>(), buffer.byteCount());
But to be honest, I am not sure why you are using a pointer.
You could just do:
QByteArray byteArr; // Your global declaration
:
:
byteArr.append(buffer.constData<char>(), buffer.byteCount());
You might want to try printing like this if you are using binary data...:
qDebug() << byteArr.toHex();
You are using method QByteArray::append which does something else than you expect. This overload of append you are using appends bytes until zero is encountered. This API should be used for c-strings!
So fix code like this:
QByteArray byteArr; // there is no point of create this on heap
byteArr.reserve(8*1024*1024); // reserve 8 MB - it will improve performance
void AudioRecorder::processBuffer(const QAudioBuffer &buffer)
{
byteArr.append(buffer.constData<char>(), buffer.size());
qDebug() << buffer.byteCount();
qDebug() << byteArr.size();
}
I'm a beginner in Qt. Now I want to use Qt5 to send a 9-byte command through uart.
Here is my command:
FFFFFF5550464DAA0E
I want to transfer my command to a Qstring object. When I write my code like this, it tells me the const is too big.
QString str=0xFFFFFF5550464DAA0E;
So I choose an array like this, but it still doesn't work.
char cmd[9]={0xFF,0xFF,0xFF,0x55,0x50,0x46,0x4D,0xAA,0x0E};
for(int i=0;i<9;i++)
{
QString str=cmd[i];
QByteArray outData=str.toLatin1();
int size=outData.size();
outData=myHelper::HexStrToByteArray(str);
size=outData.size();
myCom->write(outData);
}
I also try this which failes again
char cmd[9]={0xFF,0xFF,0xFF,0x55,0x50,0x46,0x4D,0xAA,0x0E};
QString str=cmd;
QByteArray outData=str.toLatin1();
int size=outData.size();
outData=myHelper::HexStrToByteArray(str);
size=outData.size();
myCom->write(outData);
So could anyone tell me how to do this ?
This line of code:
QString str=0xFFFFFF5550464DAA0E;
0xFFFFFF5550464DAA0E is not a string. You're trying to assign a very big constant (9 bytes) number to a string. Note that 0xFF is not a string but a character with ASCII code 0xFF. With your second attempt you're on the right way:
char cmd[9]={0xFF,0xFF,0xFF,0x55,0x50,0x46,0x4D,0xAA,0x0E};
Now you have two options; it depends on what you have to send, 9 bytes or a longer string with that commands represented as a hex string and encoded as ASCII. First case is easier, drop all your code:
QByteArray outData = QByteArray(cmd, sizeof(cmd));
myCom->write(outData);
With this code you won't send a string to your device but 9 bytes (0xFF...0x0E). If you have to send a string then you can do what paxdiablo suggested:
QByteArray outData = QByteArray("\xFF\xFF\xFF\x55\x50\x46\x4D\xAA\x0E", 9);
myCom->write(outData);
Or:
QByteArray outData = QString("0xFF0xFF0xFF0x550x500x460x4D0xAA0x0E")
.toLatin1();
myCom->write(outData);
Or in alternative you can do this:
char cmd[9]={0xFF,0xFF,0xFF,0x55,0x50,0x46,0x4D,0xAA,0x0E};
QByteArray outData = QByteArray(cmd, sizeof(cmd)).toHex();
myCom->write(outData);
Which one is right for you? Well you should clarify your context...
You don't need to mess about with strings and conversions. You can just make the QByteArray directly from the data itself, with a simple one-liner:
QbyteArray data("\xFF\xFF\xFF\x55\x50\x46\x4D\xAA\x0E", 9);
Following that, the statement:
myCom->write(data);
will then output the nine bytes as specified in the string.
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 have a problem reading more than 2048 bytes from a QLocalSocket.
This is my server-side code:
clientConnection->flush(); // <-- clientConnection is a QLocalSocket
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_0);
out << (quint16)message.size() << message; // <--- message is a QString
qint64 c = clientConnection->write(block);
clientConnection->waitForBytesWritten();
if(c == -1)
qDebug() << "ERROR:" << clientConnection->errorString();
clientConnection->flush();
And this is how I read the data in my client:
QDataStream in(sock); // <--- sock is a QLocalSocket
in.setVersion(QDataStream::Qt_5_0);
while(sock->bytesAvailable() < (int)sizeof(quint16)){
sock->waitForReadyRead();
}
in >> bytes_to_read; // <--- quint16
while(sock->bytesAvailable() < (int)bytes_to_read){
sock->waitForReadyRead();
}
in >> received_message;
The client code is connected to the readyRead signal and it's disconnected after the first call to the slot.
Why I'm able to read only 2048 bytes?
==EDIT==
After peppe's reply I updated my code. Here is how it looks now:
server side code:
clientConnection->flush();
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_0);
out << (quint16)0;
out << message;
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));
qDebug() << "Bytes client should read" << (quint16)(block.size() - sizeof(quint16));
qint64 c = clientConnection->write(block);
clientConnection->waitForBytesWritten();
client side code:
QDataStream in(sock);
in.setVersion(QDataStream::Qt_5_0);
while(sock->bytesAvailable() < sizeof(quint16)){
sock->waitForReadyRead();
}
quint16 btr;
in >> btr;
qDebug() << "Need to read" << btr << "and we have" << sock->bytesAvailable() << "in sock";
while(sock->bytesAvailable() < btr){
sock->waitForReadyRead();
}
in >> received_message;
qDebug() << received_message;
I'm still not able to read more data.
out.setVersion(QDataStream::Qt_5_0);
out << (quint16)message.size() << message; // <--- message is a QString
This is wrong. The serialized length of "message" will be message.size() * 2 + 4 bytes, as QString prepends its own length as a quint32, and each QString character is actually a UTF-16 code unit, so it requires 2 bytes. Expecting only message.size() bytes to read in the reader will cause QDataStream to short read, which is undefined behaviour.
Please do check the size of "block" after those lines -- it'll be 2 + 4 + 2 * message.size() bytes. So you need to fix the math. You can safely assume it won't change, as the format of serialization of Qt datatypes is known and documented.
I do recognize the "design pattern" of prepending the length, though. It probably comes from the fortune network example shipped with Qt. The notable difference there is that the example doesn't prepend the length of the string in UTF-16 code units (which is pointless, as it's not how it's going to be serialized) -- it prepends the length of the serialized QString. Look at what it does:
out << (quint16)0;
out << fortunes.at(qrand() % fortunes.size());
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));
First it reserves some space in the output, by writing a 0. Then it serializes a QString. Then it backtracks and overwrites the 0 with the length of the serialized QString -- which at this point, is exactly block.size() minus the prepended integer stating the lenght (and we know that the serialized length of a quint16 is sizeof(quint16))
To repeat myself, there actually two reasons about why that example was coded that way, and they're somehow related:
QDataStream has no means to recover from short reads: all the data it needs to successfully decode an object must be available when you use the operator>> to deserialize the object. Therefore, you cannot use it before being sure that all data was received. Which brings us to:
TCP has no built in mechanism for separating data in "records". You can't just send some bytes followed by a "record marker" which tells the receiver that he has received all the data pertinent to a record. What TCP provides is a raw stream of bytes. Eventually, you can (half-)close the connection to signal the other peer that the transmission is over.
1+2 imply that you must use some other mechanism to know (on the receiver side) if you already have all the data you need or you must wait for some more. For instance, you can introduce in-band markers like \r\n (like IRC or - up to a certain degree - HTTP do).
The solution in the fortune example is prepending to the "actual" data (the serialized QString with the fortune message) the length, in bytes, of that data; then it sends the length (as a 16 bit integer) followed by the data itself.
The receiver first reads the length; then it reads up that many bytes, then it knows it can decode the fortune. If there's not enough data available (both for the length - i.e. you received less than 2 bytes - and the payload itself) the client simply does nothing and waits for more.
Note that:
the design ain't new: it's what all most protocols do. In the "standard" TCP/IP stack, TCP, IP, Ethernet and so on all have a field in their "headers" which specify the lenght of the payload (or of the whole "record");
the transmission of the "length" uses a 16bit unsigned integer sent in a specific byte order: it's not memcpy()d into the buffer, but QDataStream is used on it to both store it and read it back. Although it may seem trivial, this actually completes the definition of the protocol you're using.
if QDataStream had been able to recover from short reads (f.i. by throwing an exception and leaving the data in the device), you would not have needed to send the length of the payload, since QDataStream already sends the length of the string (as a 32 bit unsigned bigendian integer) followed by the UTF-16 chars.