I am using some functions to convert QVector's to QByteArray's, for example:
QByteArray Serialize::serialize(QVector<double> data)
{
QByteArray byteArray;
QDataStream out(&byteArray, QIODevice::WriteOnly);
out << data;
return byteArray;
}
void Serialize::deserialize(QByteArray byteArray, QVector<double> *data)
{
QDataStream in(&byteArray, QIODevice::ReadOnly);
in >> *data;
}
Now, that I have the QByteArray I need to put it in a text file, how can I convert it to QString?
I already tried the simplest way:
QString myString(data); // data - QByteArray
But myString is always empty.
I also found the toStdString() function in the documentation, but it was introduced only in Qt 5.4.
I'm using Qt 5.3.
Follows a complete example:
#include <QCoreApplication>
#include <QDebug>
#include <QVector>
#include <QByteArray>
#include <QDataStream>
QByteArray serialize(QVector<double> data)
{
QByteArray byteArray;
QDataStream out(&byteArray, QIODevice::WriteOnly);
out << data;
return byteArray;
}
void deserialize(QByteArray byteArray, QVector<double> *data)
{
QDataStream in(&byteArray, QIODevice::ReadOnly);
in >> *data;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QVector<double> data;
data << 1.1 << 2.2 << 3.3 << 4.4 << 5.5 << 6.6 << 7.7 << 8.8 << 9.9;
QByteArray byteArray = serialize(data);
QVector<double> dataConverted;
deserialize(byteArray, &dataConverted);
qDebug() << "Data:";
qDebug() << data;
qDebug() << "ByteArray:";
QString test(byteArray);
qDebug() << test;
qDebug() << "Data Converted:";
qDebug() << dataConverted;
return a.exec();
}
Note: The general objective of this is to generate a SQL file with all content from the SQLite database. My double vector is converted to QByteArray and stored as BLOB into the database (using the serialize function). When I need to load it from the database I use the deserialize function to convert to a double vector again. Now I need to generate the SQL file with the data in the BLOB format, then I can directly import it into another database.
The problem is that a byte array is type-agnostic data type, it simply represents a collection of individual bytes in memory. In your example code you are creating the byte array from a vector of doubles, and then converting back to another vector of doubles. No problem.
However when you pass the byte array into the QString constructor, the QString is trying to interpret the byte array as data that represents a string, for example an array of ASCII character codes.
Some string classes might let you do this, and create an instance filled with garbage, however QString appears to be doing some basic error checking and helping you out by giving you an empty string.
As for some code to print out the contents of a byte array of doubles, the deserialize method you've provided is not too bad an example.
Use QTextCodec to convert from QByteArray to QString, here's an example from official docs:
QByteArray encodedString = "...";
QTextCodec *codec = QTextCodec::codecForName("KOI8-R");
QString string = codec->toUnicode(encodedString);
And to make the example work, you need to convert the doubles to QStrings during serialization:
QByteArray serialize(QVector<double> data)
{
QByteArray byteArray;
QDataStream out(&byteArray, QIODevice::WriteOnly);
for (double d : data) {
out << QString::number(d);
}
return byteArray;
}
If you don't want to convert individual numbers to string, you can also "stringify" the QByteArray with byteArray.toHex():
qDebug() << "ByteArray:";
QString test(byteArray.toHex());
Related
I am searching for a minimal full executable qt or c++ code example to parse and write this Json code:
{
"FirstName": "John",
"LastName": "Doe",
"MiddleName": null,
"Age": 43,
"Address": {
"Street": "Downing Street 10",
"City": "London",
"Country": "Great Britain"
},
"Phone numbers": [
"+44 1234567",
"+44 2345678"
]
"Valid":true,
}
The above example consists of an object with 5 key/value pairs. Two of the values are strings, one is a number,
one is another object and the last one an array.
A valid JSON document is either an array or an object, so a document always starts with a square or curly bracket.
EDIT:
Json has 2 more key/value pairs - value 'null' and 'bool'
And yes, I have seen a "Save Game Example"
and tried to figure it out.
But after nearly a week I gave up to transfer a minimal Example without enums, QVectors and 3 different header Files over to my project to handle the code snippet. Doesn't matter if its for a widget or core code.
I already did a xml read and write program successfully but it seems I miss some Important point and get errors with json that may or may not have to do with the parsing. I am not able to rule it out without a minimal fully working code example.
So my question is: Could you please provide a minimal Example to write, read and print the Json file? Thanks upfront.
Since there does not seem to be a clear example on SO I wrote one.
It uses simple mutation to create the objects, but if you have access to C++11 you should take a look at the std::initializer_list constructors, they make construction of objects much more compact.
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QtGlobal>
#include <QTextStream>
#include <QDebug>
int main() {
// 1. Create the document
QJsonObject root;
root["FirstName"] = "John";
root["LastName"] = "Doe";
root["Age"] = 43;
// Construct nested object first, then store it in `root`
QJsonObject Address;
Address["Street"] = "Downing Street 10";
Address["City"] = "London";
Address["Country"] = "Great Britain";
root["Address"] = Address;
QJsonArray PhoneNumbers;
PhoneNumbers.push_back("+44 1234567");
PhoneNumbers.push_back("+44 2345678");
root["Phone Numbers"] = PhoneNumbers;
// `ba` contains JSON
QByteArray ba = QJsonDocument(root).toJson();
QTextStream ts(stdout);
ts << "rendered JSON" << endl;
ts << ba;
{
QFile fout("test.json");
fout.open(QIODevice::WriteOnly);
fout.write(ba);
}
// 2. Now read it back in
QJsonParseError parseError;
QJsonDocument doc2;
{
QFile fin("test.json");
fin.open(QIODevice::ReadOnly);
QByteArray ba2 = fin.readAll();
doc2 = QJsonDocument::fromJson(ba2, &parseError);
}
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "Parse error at" << parseError.offset << ":" << parseError.errorString();
} else {
ts << "parsed JSON" << endl;
ts << doc2.toJson(QJsonDocument::Compact);
//or QJsonDocument::Indented for a JsonFormat
}
}
I guess it might help someone else too, I figured it all out,
thanks to #Botje for his example, really helped.
In general it is easy for me to remember to represent data as QByteArray
in the memory.
A minimal example to access and also use every single value stored in a json file, you are welcome:
(Yes, I could have written it even more compact but I guess this makes it easier to understand, so I spared functions/classes/structs for the sake of readability.)
#include <QCoreApplication>
#include <QString>
#include <QVariant>
#include <QFile>
#include <QByteArray>
#include <QTextStream>
#include <QDebug>
//json specific
#include <QJsonParseError>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonParseError>
#include <QJsonValue>
void writeJsonFile();
void readJsonFile();
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
writeJsonFile();
readJsonFile();
return a.exec();
}
void writeJsonFile()
{
qDebug() << "Write Json File: ";
//1. Create a QJsonObject and add values to it
QJsonObject jsonObj;
jsonObj["FirstName"] = "John";
//no value will be written as null in the json file
jsonObj["MiddleName"];
jsonObj["LastName"] = "Doe";
jsonObj["Age"] = 43;
//2. Create Item of Json Object content (object of object)
QJsonObject jsonItemObj;
jsonItemObj["Street"] = "Downing Street 10";
jsonItemObj["City"] = "London";
jsonItemObj["Country"] = "Great Britain";
//3. Add jsonItemObj to jsonObj and give it an object Name
jsonObj["Address"] = jsonItemObj;
//4. Create jsonArray and fill it with values - similar to filling a vector
QJsonArray jsonArray;
jsonArray.append("+44 1234567");
jsonArray.append("+44 2345678");
//Add a bool to the Object
jsonObj["Valid"] = true;
//5. Add jsonArray to jsonObj and give it an object Name
jsonObj["Phone numbers"] = jsonArray;
//(It can also be added to the jsonItemObj to be inline with the Address section)
//with jsonItemObj["Phone numbers"] = jsonArray or as much objects of objects
//you need
/* As I understood it, most Qt classes use a QByteArray to handle data internally
* because it is really fast/efficient,
* also QFile QIODevice, it is a good idea to hold the read/write
* QIODevice data as QByteArray in the Memory
*/
//6. Create a QByteArray and fill it with QJsonDocument (json formatted)
QByteArray byteArray;
byteArray = QJsonDocument(jsonObj).toJson();
//7. Open a QFile and write the byteArray filled with json formatted data
//thanks to the QJsonDocument() Class to the file
QFile file;
file.setFileName("file.json");
if(!file.open(QIODevice::WriteOnly)){
qDebug() << "No write access for json file";
return;
}
//8. finally write the file and close it
file.write(byteArray);
file.close();
//9. Print out the byteArray to the terminal
QTextStream textStream(stdout);
textStream << "Rendered json byteArray text: " << endl;
textStream << byteArray << endl;
}
void readJsonFile()
{
qDebug() << "Read Json File:";
//1. Open the QFile and write it to a byteArray and close the file
QFile file;
file.setFileName("file.json");
if(!file.open(QIODevice::ReadOnly)){
qDebug() << "Json filef couldn't be opened/found";
return;
}
QByteArray byteArray;
byteArray = file.readAll();
file.close();
//2. Format the content of the byteArray as QJsonDocument
//and check on parse Errors
QJsonParseError parseError;
QJsonDocument jsonDoc;
jsonDoc = QJsonDocument::fromJson(byteArray, &parseError);
if(parseError.error != QJsonParseError::NoError){
qWarning() << "Parse error at " << parseError.offset << ":" << parseError.errorString();
return;
}
//3. Create a jsonObject and fill it with the byteArray content, formatted
//and holding by the jsonDocument Class
QJsonObject jsonObj;
jsonObj = jsonDoc.object();
//4. Now picking the jsonValues and printing them out or do what ever you need
QJsonValue jsonVal;
QTextStream textStream(stdout);
jsonVal = jsonObj.value("FirstName");
textStream << jsonVal.toString() << endl;
jsonVal = jsonObj.value("MiddleName");
//null gets back to an empty fild - added the sting "null/empty" to make it visible
textStream << jsonVal.toVariant().toString() << "null/empty" << endl;
jsonVal = jsonObj.value("LastName");
textStream << jsonVal.toString() << endl;
//The number has to be converted to an int and than to a string to print it
jsonVal = jsonObj.value("Age");
textStream << QString::number(jsonVal.toInt()) << endl;
//5. Now we need to fill the object of the object. To do that, we need
//the Item Object and a jsonSubVal object for json without a loop
QJsonObject jsonItemObj;
QJsonValue jsonSubVal;
jsonVal = jsonObj.value(QString("Address"));
jsonItemObj = jsonVal.toObject();
jsonSubVal = jsonItemObj["Street"];
textStream << jsonSubVal.toString() << endl;
jsonSubVal = jsonItemObj["City"];
textStream << jsonSubVal.toString() << endl;
jsonSubVal = jsonItemObj["Country"];
textStream << jsonSubVal.toString() << endl;
//6. now the Phone Numbers array with a loop
QJsonArray jsonArray;
jsonArray = jsonObj["Phone numbers"].toArray();
for(int i = 0; i < jsonArray.size(); i++)
textStream << jsonArray[i].toString() << endl;
textStream << "or with foreach" << endl;
foreach(QJsonValue v, jsonArray)
textStream << v.toString() << endl;
//7. And finally the bool value:
jsonVal = jsonObj.value(QString("Valid"));
textStream << jsonVal.toVariant().toString() << endl;
textStream << "or as number, not a string: ";
textStream << (QString::number(jsonVal.toInt())) << endl;
textStream << "\nThe whole file as printed in the file \n" <<
jsonDoc.toJson(QJsonDocument::Indented);
I want to create istream from QByteArray at runtime, without saving a physical file in memory of QByteArray.
I found that there are many ways to do the opposite conversion, i.e. istream to QByteArray, but not this one.
How to accomplish that?
To read via std::istringstream from QByteArray seems quite easy:
testQByteArray-istream.cc:
#include <iostream>
#include <sstream>
#include <QtCore>
int main()
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
// make a QByteArray
QByteArray data("Hello Qt World.");
// convert to std::string
std::istringstream in(data.toStdString());
// read from istringstream
for (;;) {
std::string buffer;
if (!std::getline(in, buffer)) break;
std::cout << "Got: '" << buffer << "'\n";
}
// done
return 0;
}
testQByteArray-istream.pro:
SOURCES = testQByteArray-istream.cc
QT = core
Compiled and tested on cygwin64:
$ qmake-qt5 testQByteArray-istream.pro
$ make
$ ./testQByteArray-istream
Qt Version: 5.9.4
Got: 'Hello Qt World.'
$
Done. Stop, wait!
without saving a physical file in memory
I'm not quite sure how to read this. Probably, it means
without copying data saved in QByteArray
I see only two solutions:
Use a QDataStream instead of std::stream. According to doc. QDataStream::QDataStream(const QByteArray &a)
Constructs a read-only data stream that operates on byte array a.
This sounds very promising that data is not copied.
DIY. Make a class derived from std::stream which may read from a QByteArray without copying.
Concerning 2. option, I found Dietmar Kühl's answer to SO: Creating an input stream from constant memory. Applying this to the above sample, it would look like this:
#include <iostream>
#include <QtCore>
// borrowed from https://stackoverflow.com/a/13059195/7478597
struct membuf: std::streambuf {
membuf(char const* base, size_t size) {
char* p(const_cast<char*>(base));
this->setg(p, p, p + size);
}
};
struct imemstream: virtual membuf, std::istream {
imemstream(char const *base, size_t size):
membuf(base, size),
std::istream(static_cast<std::streambuf*>(this)) {
}
};
int main()
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
// make a QByteArray
QByteArray data("Hello Qt World.");
imemstream in(data.data(), (size_t)data.size());
// read from istringstream
for (;;) {
std::string buffer;
if (!std::getline(in, buffer)) break;
std::cout << "Got: '" << buffer << "'\n";
}
// done
return 0;
}
Compiled and tested again on cygwin64:
$ qmake-qt5 testQByteArray-istream.pro
$ make
$ ./testQByteArray-istream
Qt Version: 5.9.4
Got: 'Hello Qt World.'
$
Up until now, I output everything using qDebug().noquote(). This is easy because it just requires a simple #import <QDebug>
Now I need everything to output to stdout, but I don't know how to do it easily. This how I was taught:
QTextStream cout(stdout, QIODevice::WriteOnly);
However, creating a new object is a tad bit more cumbersome than a simple #import <QDebug>. What is the good/least cumbersome way to handle stdout in qt?
qDebug(), qInfo(), etc. are all piped to a default message handler. But you can easily install your own that writes the debug strings to a different stream, file, or anything. All you need to do is define a message handler function and install it using qInstallMessageHandler().
Putting it all together, here's a complete example:
#include <QDebug>
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
QTextStream cout(stdout, QIODevice::WriteOnly);
cout << msg << endl;
}
int main(int argc, char *argv[])
{
qInstallMessageHandler(myMessageOutput);
qDebug().noquote() << "Hello world!";
}
The best way is the one you mentioned. You don't have to create a new local variable:
QTextStream(stdout) << "Hello world!" << endl;
If the source text is not Latin-1 encoded then you need to convert to QString before passing it to the stream operator:
QTextStream(stdout) << QString::fromUtf8("utf8 literal") << endl;
I'm new in Qt and can't find any solution in Qt libraries.
I'd like to find smth without loop usage.
Is there any way to convert QByteArray to QString with - between bytes?
For example:
QByteArray = XX1F2C5A
QString = "XX-1F-2C-5A".
Yeah you can with QString::replace:
QByteArray b = "XX1F2C5A";
QString s(b);
qDebug() << s;
s.replace(QRegExp("(..)[^$]"), QString("\\1-"));
qDebug() << s;
I am using Qt (5.5) and I want to exchange data in JSON format in a client-server application.
So the format is constant:
{
"ball":
{
"posx": 12,
"posy": 35
}
}
I would like to be able to define a ByteArray or string like so:
QByteArray data = "{\"ball\":{\"posx\":%s,\"posy\":%s}}"
and then just write whatever the values for that into the string.
How do I do that?
QtJson is baked into Qt 5. It is easy to use, and gets it all ready for you pretty easily.
#include <QCoreApplication>
#include <QDebug>
#include <QJsonObject>
#include <QJsonDocument>
void saveToJson(QJsonObject & json);
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QJsonObject jsonObject;
saveToJson(jsonObject);
QJsonDocument jsonDoc(jsonObject);
qDebug() << "Example of QJsonDocument::toJson() >>>";
qDebug() << jsonDoc.toJson();
qDebug() << "<<<";
return a.exec();
}
void saveToJson(QJsonObject & json)
{
QJsonObject ball;
ball["posx"] = 12;
ball["posy"] = 35;
json["ball"] = ball;
}
output
Example of QJsonDocument::toJson() >>>
"{
"ball": {
"posx": 12,
"posy": 35
}
}
"
<<<
Note: qDebug() wraps QString objects in quotes when printing. To get rid of that, pass your QString into qPrintable(). And it puts endl in for you at the end of each line.
For a more complex example see the official:
JSON Save Game Example
http://doc.qt.io/qt-5/qtcore-json-savegame-example.html
Hope that helps.
And here are more examples of string manipulations, but for readability and maintainability, please use the QJson classes.
QString str;
str = QString("{\"ball\":{\"posx\":%1,\"posy\":%2}}").arg(12).arg(35);
qDebug() << qPrintable(str);
QByteArray ba = str.toLocal8Bit();
qDebug() << ba;
QString str2;
str2 = "{\"ball\":{\"posx\":"
+ QString::number(12)
+ ",\"posy\":"
+ QString::number(35)
+ "}}";
qDebug() << qPrintable(str2);
output
{"ball":{"posx":12,"posy":35}}
"{"ball":{"posx":12,"posy":35}}"
{"ball":{"posx":12,"posy":35}}
Note again that the quotes are added by qDebug() when printing a QByteArray object.
Hope that helps.