[SOLVED] Best way of reading bytes (with specific length) from QDataStream to QByteArray
-
Greetings!
I am using QDatastream to read bytes of specific length and saving it into a QByteArray. Right now I am using the following code:
@QDataStream input(...);
QByteArray buffer;
int length = ...;
...
quint8 byte;
for(int i=0; i<length; ++i) {
input >> byte;
buffer.append(byte);
}@The code is working but I am looking for a more optimized way since I think this is very slow especially when length is too big. I came across QDataStream::readRawData() and QDataStream::readBytes() but I don't know how to implement them since a QByteArray is '\0'-terminated and char* is not. Thanks!
-
Hi,
The QDateSteam is most likely set to a QIODevice? You should be able to use the readyRead() function of the QIODevice when new data is ready to be read. Or in the handling slot check the amount of bytes ready to read, then when all is in, read all available data with the int readRawData ( char * s, int len ) making sure the len is smaller then the QByteArray size!!!
That should do the trick I think.
Greetz -
Hi you can use code like this
@
QDataStream input (...);
QByteArray buffer;
int length = ...;char temp [length];
input.readRawData (temp, length);
buffer.append (temp, length);
@or
@
QDataStream input (...);
QByteArray buffer;
int length = ...;char temp* = 0;
input.readBytes (temp, length);
buffer.append (temp, length);
delete [] temp;
@ -
[quote author="Jeroentje@home" date="1367577761"]Hi,
The QDateSteam is most likely set to a QIODevice? You should be able to use the readyRead() function of the QIODevice when new data is ready to be read. Or in the handling slot check the amount of bytes ready to read, then when all is in, read all available data with the int readRawData ( char * s, int len ) making sure the len is smaller then the QByteArray size!!!
That should do the trick I think.
Greetz[/quote]I am sorry if I wasn't too clear with it. The problem is not with QDataStream or with signal-slot implementation. I am reading a "binay file" and data/device is already available. It has a specific structure (header, etc.) and let's say I was able to obtain the "length", next thing to do is to read the succeeding bytes (using the length specified, of course) and saving it into a QByteArray. I wanted to find a better alternative in the "for" loop in the above code.
-
Thank you @mcosta. The second code works (but changing "char temp* = 0"; into "char *temp = 0;").
However, it became slower. I am using QElapsedTimer to check for speed.
Reading the same file, my code results to 67847 nsecs
while the code you suggested results to 859396 nsecs
which is a big number for me. -
Thank you again mcosta, the first code results into a better speed.
@QElapsedTimer timer; //for measuring speed in nsecs
timer.start();
char *temp = new char[length]; //need to change into this, compiler throws error: "expected constant expression"
input.readRawData(temp, length);
buffer.append(temp, length);
delete [] temp;
qDebug() << timer.nsecsElapsed();@Your code = 22134 nsecs
My code = 57742 nsecsNOTE: QElapsedTimer is NOT accurate but I think it is PRECISE.
Thanks. It is now solved!
-
Hi, what might speed up the process is to not copy the data into a temp buffer.
Maybe something like this:
@
QByteArray newBuf(file.readAll ());
@
Then the newBuf will be a deep copy of the data from the file. You could also use the read(length) function of the QIODevice.
The question that comes to mind now is why you really need the QDataStream Input if you copy the entire contense of the file anyway?
Maybe I'm missing the big picuture here, but hope I could be of assistance anyway.
Greetz -
@Code_Reaqtor
What does my option give you as a result? Just curious to know.
Greetz -
[quote author="Jeroentje@home" date="1367580778"]What does my option give you as a result? Just curious to know.
Greetz[/quote]The reason why is that I am reading a "binary file" and it has a structure composed of "blocks", etc. each block has a specific size/length. It can't be done by reading the whole file. QDataStream works better. Take the example below, it "simply" shows the structure of the file:
@Size of Block 1
Content of Block1
Size of Block2
Content of Block2
Size of Block3
Content of Block3
...etc@PS: This is not the "real" file structure. It is just an example.
-
Ah, Oke,
Got it.
If you only open the file ones and read out all the blocks in sequence you still could do it with an QIODevice option. The file will be kept at the position it was last read, so a sequence of read(xbytes) will shift the file reader only as far as the read takes it. Still no need to copy the data ;-)
Don't want to say you option is bad or wrong!! Just because you needed the ultimate fast speed it might be faster then coping data multiple times:
1 - QDataStream to temp buffer
2 -temp buffer to QByteArray
The Qfile inherits QIODevice, so is able to do read and peek, so the:
@
QByteArray newBuffer (file.read(yourdesiredsize));
@
This voids the double extra copy if I'm not mistaken, but as said before, it might not be suitable in your case if the file is opened/closed etc. -
@Jeroentje, yes I think that speeds up access. I might take that as an option. But for now I'll stick with the current method.
BTW, "this":https://github.com/Code-ReaQtor/libqpsd is the code I am talking about. The structure is a little complicated so I can't think of better ways in integrating your method.
Thank you all for suggestions!