How to append json data into existing json file in Qt - c++

I am creating .json file and I'm trying to append new data into json file. For that I call append file instead of writeonly file but get error at console "Error loading JSON: "garbage at the end of the document" # 548" How to append json file?
/*-------------Write data into files ------------*/
void addLogs(QString flightType, QString flightTextLogs){
QFile file("FlightNotifications.json"); // json file
file.open(QFile::WriteOnly ); // Append
QJsonObject m_projectDetails;
qint64 qiTimestamp=QDateTime::currentMSecsSinceEpoch();
QDateTime dt;
dt.setTime_t(qiTimestamp/1000);
m_projectDetails.insert("Type", flightType);
m_projectDetails.insert("TextLog", flightTextLogs);
m_projectDetails.insert("Date and Time",dt.toString("yyyy-MM-dd hh:mm:ss"));
rootObject.insert("Notifications",m_projectDetails);
rootObject1.append(rootObject);
QJsonDocument doc1(rootObject1);
file.write(doc1.toJson());
file.close();
}
/*--------------- Read json file-----------------*/
void readFlightLogs(){
qDebug()<<"Read data";
QByteArray val;
QFile file("FlightNotifications.json");
if(file.exists())
{
file.open(QIODevice:: ReadOnly | QIODevice::Text);
val = file.readAll();
file.close();
QJsonParseError jspe{};
const QJsonDocument doc = QJsonDocument::fromJson(val, &jspe);
if (doc.isNull())
{
qWarning() << "Error loading JSON:" << jspe.errorString() << "#" << jspe.offset;
}
QJsonArray jsonArray = doc.array();
if(jsonArray.size()<1)
{
}
for (int i=0; i < jsonArray.size(); i++)
{
QJsonObject temp = jsonArray.at(i).toObject();
FlightNotificationList ::getInstance()-> addAsset(temp.value("Notifications").toObject().value("Type").toString(),
temp.value("Notifications").toObject().value("TextLog").toString(),
temp.value("Notifications").toObject().value("Date and Time").toString(),
"name");
qDebug() << temp.value("Notifications").toObject().value("Type").toString();
qDebug() << temp.value("Notifications").toObject().value("TextLog").toString();
qDebug() << temp.value("Notifications").toObject().value("Date and Time").toString();
}
}
}
When I use QFile::WriteOnly the file gets override. How to append .json file

You should load the whole json array content, insert new item then rewrite the json array to disk.
The addLogs function could be rewritten as :
/*-------------Write data into files ------------*/
bool addLogs(QString flightType, QString flightTextLogs){
QFile file("FlightNotifications.json"); // json file
if( !file.open( QIODevice::ReadOnly ) ) //read json content
{
//open file error ...
return false;
}
QJsonDocument jsonOrg = QJsonDocument::fromJson( file.readAll() );
file.close();
//local variable, do not use m_ prefix.
QJsonObject projectDetails = { {"Type", flightType},
{"TextLog", flightTextLogs},
{"Date and Time", QDateTime::currentDateTime().toString( "yyyy-MM-dd hh:mm:ss" )} };
QJsonObject notificationObj = {{ "Notifications", projectDetails }};
QJsonArray arrLog = jsonOrg.array();
arrLog.push_back( notificationObj );
QJsonDocument doc( arrLog );
if( !file.open( QIODevice::WriteOnly ) ) //write json content to file.
{
//cannot open for write ...
return false;
}
file.write(doc.toJson());
file.close();
return true;
}

you should open the file in append mode too: (QIODevice::Append)
myFile.open(QIODevice::WriteOnly | ... | QIODevice::Append)

Related

QT 6: "Exception thrown: read access violation e was 0xFFFFFFFFFFFFFFF7" when trying to read Json from a file

I am trying to read Json from a file, that I have previously created using QT, so it should be proper Json. Furthermore I have already implemented such a functionality in another program of mine, in which it worked fine and still works, so I basically copied the functions into the new program, but now I am recieving a weird error and cant fix it.
Error: "Exception thrown: read access violation.
e was 0xFFFFFFFFFFFFFFF7."
kegelbuch.cpp(void Kegelbuch::load(QString path):
void Kegelbuch::load(QString path, QString tab) {
//Load json file
Datastream* loadStream = new Datastream;
QJsonObject data = loadStream->loadData(path); //Error
if (data.contains("KeglerFullName") && data["KeglerFullName"].isArray()) {
QJsonArray keglerFullName = data["KeglerFullName"].toArray();
for (auto fullName : keglerFullName) {
if (fullName.isString()) {
QLineEdit* fullNameEdit = new QLineEdit;
fullNameEdit->setText(fullName.toString());
ui.keglerTab->layout()->addWidget(fullNameEdit);
}
}
}
else if (data.contains("KeglerShortName") && data["KeglerShortName"].isArray()) {
QJsonArray keglerShortName = data["KeglerShortName"].toArray();
for (auto shortName : keglerShortName)
{
if (shortName.isString()) {
QLineEdit* shortNameEdit = new QLineEdit;
shortNameEdit->setText(shortName.toString());
ui.keglerTab->layout()->addWidget(shortNameEdit);
}
}
}
}
datastream.cpp(const QJsonObject& Datastream::loadData(QString path)):
const QJsonObject& Datastream::loadData(QString path) {
QFile loadFile(saveFormat == Json
? QStringLiteral("data.json")
: QStringLiteral("data.dat"));
if (!loadFile.open(QIODevice::ReadOnly)) {
qWarning("Couldn't find/open the save file.");
QJsonObject returnObject;
return returnObject;
}
QByteArray saveData = loadFile.readAll();
QJsonDocument loadDoc(saveFormat == Json
? QJsonDocument::fromJson(saveData)
: QJsonDocument(QCborValue::fromCbor(saveData).toMap().toJsonObject()));
return loadDoc.object();
}
data.json
{
"KeglerFullName": [
"sadfg",
"ftzjtzc",
"restes",
"sxrtfgh"
],
"KeglerShortName": [
"waf",
"drxht",
"dsfgh",
"dft"
]
}
Thanks!

How to parse this JSON wit Qt an C++?

I have a json like this:
{
"name1": {
"path": "D:/myfolder"
},
"name2": {
"path": "D:/anotherFolder"
},
"name3": {
"path": "D:/myfolder"
}
}
And I want to get: are the names and the folder names.
like :
name1, D:/myfolder
name2, D:/anotherFolder
name3, D:/myfolder
It is not important if i get them independently or in an map, because i want to save them
to new variables into another struct.
what I have so far is:
QString jsonFile = "myjson.json";
QFile loadFile(jsonFile);
if(!loadFile.open(QIODevice::ReadOnly)){
qDebug() << "Failed to open " << loadFile; }
QByteArray data = loadFile.readAll();
QJsonDocument loadDoc(QJsonDocument::fromJson(data));
QJsonObject json = loadDoc.object();
QStringList keys = json.keys(); // <------- that give me the names. check.
But i didnt get it: how to get the second element?!?
the nearest approche so far was to get the "2nd dimension" with foreach:
foreach(const QJsonValue path, json ){
qInfo() << path;
}
this gave me as output:
QJsonValue(object, QJsonObject({"path": "D:/myfolder"}))
QJsonValue(object, QJsonObject({"path": "D:/anotherFolder"}))
QJsonValue(object, QJsonObject({"path": "D:/myfolder"}))
Most optimal way to do it just using single for iteration
QJsonDocument doc = QJsonDocument::fromJson(data);
QJsonObject json = doc.object();
for (auto it = json.constBegin(); it != json.constEnd(); ++it)
{
qInfo() << it.key() << it.value().toObject().value("path").toString();
}
You have to iterate through the keys obtaining the value, and then access the last one using the key "path":
QJsonDocument loadDoc = QJsonDocument::fromJson(data);
QJsonObject json = loadDoc.object();
for(const QString & key : json.keys()){
qInfo() << key << json[key].toObject()["path"].toString();
}

How to write/Read Json file

I have written a program in C++, Now, I can read the JSON file and I can able to execute the instructions. Here I have attached Sample JSON file (Pre defined), As per the Json instruction program will execute, when it will reach the end coordinate the program will stop.
For starting and stopping string received from the server through web socket. If the start button clicked from server, application will start, In Json file I have defined the mapping coordinate start_x, start_y when it will reach the end_x, end_y coordinate the application will stop.
Now, I want to sent the start_x, start_y, end_x, end_y coordinate from server. Whenever the coordinate values are coming from server that should update (Change/Write) the coordinate values in JSON, not only values, whatever the string sending from server. I know how to read JSON and execute the instruction, I don't know how to write, replace, update JSON from server. Then I want to execute the instructions.
Jsonfile.js
{
"ID" : "NO1",
"action" : "start",
"zone" :
{
"start_x" : 0,
"start_y" : 4,
"end_x" : 10,
"end_y" : 5,
"motion" :
{
"motion_type": "Linear",
"degree_of_rotation": 30,
"rotation_direction": "clock",
"linear_direction": "+ve"
}
}
}
Jsonfileread.cpp
qDebug() <<"file reading";
file.setFileName("/PROJECT/JSON/jsonfile.js");
file.open(QIODevice::ReadOnly | QIODevice::Text);
if (!file.exists()){
cout<<"file found"<<endl;
}
QFileDevice::FileError err = QFileDevice::NoError;
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() <<"Could not open file : "<<file.fileName() <<"for reading :"<<file.errorString()<<endl;
errMsg =file.errorString();
err =file.error();
cout<<"err : "<<err<<endl;
}
settings = file.readAll();
if (file.error() != QFile::NoError) {
qDebug() << QString("Failed to read from file %1, error: %2").arg(file.fileName()).arg(file.errorString());
}
if (settings.isEmpty()) {
qDebug() << "No data was currently available for reading from file" << file.fileName();
}
file.close();
object = EchoClient::jsonstringflag;
QJsonDocument sd = QJsonDocument::fromJson(settings.toUtf8());
QJsonObject sett2 = sd.object();
QJsonValue mainid = sett2["ID"];
mainid = mainid.toString();
QJsonValue action = sett2["action"];
actionstring = action.toString();
QJsonValue value = sett2.value(QString("zone"));
QJsonObject item = value.toObject();
QJsonValue startx = item["start_x"];
startvaluex = startx.toInt();
QJsonValue starty = item["start_y"];
startvaluey = starty.toInt();
QJsonValue endx = item["end_x"];
endvaluex = endx.toInt();
xendvaluestring = endx.toString();
QJsonValue endy = item["end_y"];
endvaluey = endy.toInt();
yendvaluestring = endy.toString();
Kindly assist me to solve this issue.

QSettings: How to read array from INI file

I wanna read comma separated data form INI file. I've already read here:
QSettings::IniFormat values with "," returned as QStringList
How to read a value using QSetting if the value contains comma character
...that commas are treated as separators and QSettings value function will return QStringList.
However, my data in INI file looks like this:
norm-factor=<<eof
1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0
1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0
1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0
1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0
1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0
1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0
eof
I don't need a whole matrix. All rows joined up together are fair enough for me. But can QSettings handle such structure?
Should I read this using:
QStringList norms = ini->value("norm-factor", QStringList()).toStringList();
Or do I have to parse it in another way?
The line breaks are a problem since INI files use line breaks for their own syntax.
Qt seems to not support your type of line continuation (<<eol ... eol).
QSettings s("./inifile", QSettings::IniFormat);
qDebug() << s.value("norm-factor");
yields
QVariant(QString, "<<eof")
The <<eol expression might be invalid INI in itself. (Wikipedia on INI files)
I suggest you parse the file manually.
Ronny Brendel's answer is correct ...i am only adding code that solves above problem ...it creates temporary INI file with corrected arrays:
/**
* #param src source INI file
* #param dst destination (fixed) INI file
*/
void fixINI(const QString &src, const QString &dst) const {
// Opens source and destination files
QFile fsrc(src);
QFile fdst(dst);
if (!fsrc.open(QIODevice::ReadOnly)) {
QString msg("Cannot open '" + src + "'' file.");
throw new Exception(NULL, msg, this, __FUNCTION__, __LINE__);
}
if (!fdst.open(QIODevice::WriteOnly)) {
QString msg("Cannot open '" + dst + "'' file.");
throw new Exception(NULL, msg, this, __FUNCTION__, __LINE__);
}
// Stream
QTextStream in(&fsrc);
QTextStream out(&fdst);
bool arrayMode = false;
QString cache;
while (!in.atEnd()) {
// Read current line
QString line = in.readLine();
// Enables array mode
// NOTE: Clear cache and store 'key=' to it, without '<<eof' text
if (arrayMode == false && line.contains("<<eof")) {
arrayMode = true;
cache = line.remove("<<eof").trimmed();
continue;
}
// Disables array mode
// NOTE: Flush cache into output and remove last ',' separator
if (arrayMode == true && line.trimmed().compare("eof") == 0) {
arrayMode = false;
out << cache.left(cache.length() - 1) << "\n";
continue;
}
// Store line into cache or copy it to output
if (arrayMode) {
cache += line.trimmed() + ",";
} else {
out << line << "\n";
}
}
fsrc.close();
fdst.close();
}

How can I zip a directory/folder with quazip?

I have a directory with files and folders that I would like to zip. I'm using the qt-project quazip for it. So I thought I write a function that packs all content of a directory including the filestructure.
How can I create the folder in the zip-file? I tried it with QuaZipNewInfo but couldn't make it work.
For example I want to zip the tmp-folder with this content:
tmp/1.txt
tmp/folder1/2.txt
tmp/folder1/3.txt
tmp/folder2/4.txt
tmp/folder2/folder3/5.txt
What I get after extracting the file with a common archive-tool (Archive Utility) is this:
tmp/1.txt
tmp/2.txt
tmp/3.txt
tmp/4.txt
tmp/5.txt
This is what I have so far:
void Exporter::zipFilelist(QFileInfoList& files, QuaZipFile& outFile, QFile& inFile, QFile& inFileTmp)
{
char c;
foreach(QFileInfo file, files) {
if(file.isDir() && file.fileName() != "." && file.fileName() != "..") {
QFileInfoList infoList = QDir(file.filePath()).entryInfoList();
zipFilelist(infoList, outFile, inFile, inFileTmp);
}
if(file.isFile()) {
inFileTmp.setFileName(file.fileName());
inFile.setFileName(file.filePath());
if(!inFile.open(QIODevice::ReadOnly)) {
qDebug() << "testCreate(): inFile.open(): " << inFile.errorString().toLocal8Bit().constData();
}
QuaZipNewInfo info(inFileTmp.fileName(), inFile.fileName());
if(!outFile.open(QIODevice::WriteOnly, info)) {
qDebug() << "testCreate(): outFile.open(): " << outFile.getZipError();
}
while(inFile.getChar(&c)&&outFile.putChar(c)) ;
if(outFile.getZipError()!=UNZ_OK) {
qDebug() << "testCreate(): outFile.putChar(): %d"<< outFile.getZipError();
}
outFile.close();
if(outFile.getZipError()!=UNZ_OK) {
qDebug() << "testCreate(): outFile.close(): %d"<< outFile.getZipError();
}
inFile.close();
}
}
}
And this is how I call the function:
QFileInfoList files = QDir(sourceFolder).entryInfoList();
QFile inFile;
QFile inFileTmp;
QuaZipFile outFile(&zip);
zipFilelist(files, outFile, inFile, inFileTmp);
I don't get any error. When I want to unzip the file it doesn't extract the folders (because I probably don't pack them into the zip!?). So I get all files of all subfolders unziped into one folder.
It seems that in your function you were recursively getting the files in the folders, but not the folders themselves. Try creating a folder to zip the files into when you recurse into looking for the files in the subdirectory.
You may want to look into this answer:
https://stackoverflow.com/a/2598649/1819900
How about the utilities provided by QuaZip?
http://quazip.sourceforge.net/classJlCompress.html
When creating the QuaZipNewInfo object, specify the path and file name to your file as you want to store it in the zip as the first argument, and the path and file name to your file on disk as the second argument. Example:
Adding C:/test/myFile.txt as test/myFile.txt in zip:
QuaZipNewInfo("test/myFile.txt", "C:/test/myFile.txt")
In order to create a folder in your zip file, you need to create an empty file with a name ending with "/". The answer does not include the listing of files/folders but focuses on creating folders in zip file.
QDir sourceRootDir("/path/to/source/folder");
QStringList sourceFilesList; // list of path relative to source root folder
sourceFilesList << "relativePath.txt" << "folder" << "folder/relativePath";
QualZip zip("path/to/zip.zip");
if(!zip.open(QuaZip::mdCreate)){
return false;
}
QuaZipFile outZipFile(&zip);
// Copy file and folder to zip file
foreach (const QString &sourceFilePath, sourceFilesList) {
QFileInfo sourceFI(sourceRootDir.absoluteFilePath(sourceFilePath));
// FOLDER (this is the part that interests you!!!)
if(sourceFI.isFolder()){
QString sourceFolderPath = sourceFilePath;
if(!sourceFolderPath.endsWith("/")){
sourceFolderPath.append("/");
}
if(!outZipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(sourceFolderPath, sourceFI.absoluteFilePath()))){
return false;
}
outZipFile.close();
// FILE
} else if(sourceFI.isFile()){
QFile inFile(sourceFI.absoluteFilePath());
if(!inFile.open(QIODevice::ReadOnly)){
zip.close();
return false;
}
// Note: since relative, source=dst
if(!outZipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(sourceFilePath, sourceFI.absoluteFilePath()))){
inFile.close();
zip.close();
return false;
}
// Copy
qDebug() << " copy start";
QByteArray buffer;
int chunksize = 256; // Whatever chunk size you like
buffer = inFile.read(chunksize);
while(!buffer.isEmpty()){
qDebug() << " copy " << buffer.count();
outZipFile.write(buffer);
buffer = inFile.read(chunksize);
}
outZipFile.close();
inFile.close();
} else {
// Probably simlink, ignore
}
}
zip.close();
return true;