QXmlStreamWriter crashes when I try to write too many items - qt

I am using QXmlStreamWriter to create an xml file with many items. At one point because there are too many elements probably I experience a crash.
Is there a way to perform a flush on the stream?
How else can I perform the writing so I do not experience a crash?

Found out that QByteArray doesn't support more than 2GB. That's why i had a crash. I used QXmlStreamWriter together with a QByteArray.
If I provide the file directly it works fine.
previous code:
QByteArray buffer;
QXmlStreamWriter stream(&buffer);
current code:
QFile* destFile
QXmlStreamWriter stream(destFile);

Related

Qt: How to lock/prevent a file from being read while it is written?

I am using Qt5 on Windows 7.
In my current project I open a binary file in order to populate it with data coming from a TCP socket.
Normally, after the file is populated, I close it and another application will read this binary file for further processing.
Well, the problem is: The writing operation takes about 4-5 seconds (or even more) so I need to find a way to prevent the other application from reading from the binary file until the file is completely populated...
Here below is the code (yet I suppose it won't help much):
int error = 0;
unsigned long dataLength;
char dataBuffer[1500];
QFile localFile("datafile.bin");
//
localFile.open(QIODevice::WriteOnly);
while(error == 0)
{
error = readSocket(dataBuffer, &dataLength);
if(error == 0)
{
localFile.write(dataBuffer, dataLength);
}
else
{
error = -1;
}
}
localFile.close();
I am thinking about using a temporary file and rename it after the write operation is complete.
But maybe there is another better/smarter idea? Some kind of "lock file for reading" maybe...?
If you have the source to both applications, then the one writing the file can signal the other application by one of many IPC mechanisms (e.g. local sockets) that it has finished writing.
Alternatively, write to a file with a different filename and then rename / copy the file to the location expected by the reading application, when the write has finished.
However, it is advisable to use QSaveFile, rather than QFile when writing out files. As the documentation states: -
While writing, the contents will be written to a temporary file, and if no error happened, commit() will move it to the final file
So this will likely solve the problem for you.
I know maybe it's a little bit too late, but I recently found an interesting solution, i.e. a component named "Locked File":
The QtLockedFile class extends QFile with advisory locking functions.
This class extends the QFile class with inter-process file locking
capabilities. If an application requires that several processes should
access the same file, QtLockedFile can be used to easily ensure that
only one process at a time is writing to the file, and that no process
is writing to it while others are reading it.
class QtLockedFile : public QFile
{
public:
enum LockMode { NoLock = 0, ReadLock, WriteLock };
QtLockedFile();
QtLockedFile(const QString &name);
~QtLockedFile();
bool open(OpenMode mode);
bool lock(LockMode mode, bool block = true);
bool unlock();
bool isLocked() const;
LockMode lockMode() const;
private:
LockMode m_lock_mode;
};
This link will lead you to the right place, where the QLockedFile class implementation is:
https://github.com/kbinani/qt-solutions/tree/master/qtlockedfile
** So, I decided to share this info, maybe other Qt-users are interested! **

Serialize QFileInfo

I have a list of files and I'd like to serialize the file info for every file and send it through socket.
I saw it's possible to serialize like this for example:
QByteArray ba;
QDataStream ds(&ba);
ds << my_stringlist;
QByteArray ba;
QDataStream ds(&ba);
ds >> my_stringlist;
but I couldn't find support for QFileInfo. Is it possible to serialize this Qt data type?
Is there any way to get an easy full serialization of this type or I just need to break up the data into primitive units?
There is no standard way to do that. You can define your custom QDataStream operators as showed in this answer, or you can write your own functions to convert QFileInfo to QVariant and back, and use QVariant serialization. In all these ways you need to break up the data into primitive units, yes.
However I think serializing QFileInfo is pointless. You should use QFileInfo::absoluteFilePath() to get the file's path and serialize that path instead. A new QFileInfo object can be easily constructed from that path if your receiving code is running on the same machine.
If your code is running on the other machine, you couldn't use deserialized QFileInfo even if it would be possible. It's because QFileInfo may or may not store information about file. When you run e.g. QFileInfo::isFile, it may make a request to the underlying file system.
So I think it's better to request all required data from QFileInfo add send this data instead of sending QFileInfo. Or you can just send the absolute file path.

QVariantMap crash in destructor

I am building a JSON-object with Qt and convert it to a QString using QJson. This (normally) works fine and it does in this case but in the destructor of my Qt data structure, it crashes with an Access Violation. The Object is built fine, it is sent over my network connection and after the function ends, my application crashes.
My code looks like this:
void bar()
{
QVariantMap data;
data.insert("Id", 1);
QList<QVariant> list; //QVariantList
for (QMap<...>:ConstIterator ... ) //Loop through a Map
{
QMap<QString, QVariant> singleEntry; //QVariantMap
singleEntry.insert("LocalId", it.value());
QList<QVariant> entryList; //QVariantList
for (...) //Loop through another structure
{
entryList.append("foo");
}
singleEntry.insert("List", entryList);
list.append(singleEntry);
}
data.insert("Entries", list);
QJson::Serializer.serialize(data); // Works fine
} // Crash here
If I remove the inner loop, which builds up entryList, everything works fine. It seems that the destructor of data cannot delete the contents but I have no idea, why. The whole data structure seems to be fine while serializing it (and I hope that QJson does not change anything in the given data) but it cannot be cleaned up..
Best Regards,
Tobias
As Raiv said this can happen when mixing debug and release dlls, but in my oppinion this can also happen if the application and the Qt DLL's use different CRT libraries. Some people say that when they recompiled Qt on their machines the problem dissapears and I think this is because the CRT dlls after Qt rebuild are the same as the app's. Try to set the Runtime Library option in C/C++ Code Generation is set to Multi-threaded Debug DLL (/MDd) or Multi-threaded DLL (/MD) respectively for Debug and Release. Some Qt types as QVariantMap, QVariantList, QModelIndexList are probably allocated with /MD (in Qt's dll) and when they are deallocated with /MT (in the app) I think this causes the crash. This can also fix the crash on QString::toStdWString(). In order for this to link maybe the Ignore All Default Libraries should be set to No and Ignore Specific Library should not mention crt dlls used by Qt.
I got a little workaround, which fits my needs. I have still no idea, why this crash happens, but I know, which should be the problem.
I tried to build up a static structure like this:
QVariantMap
QVariantList
QVariantMap
QVariantList
and it crashes. If I remove the QVariantList at the bottom and add QVariantMap or anything else instead, it is working fine. I think this is a problem with the nesting level in this case.
I have now just joined my list as a comma-seperated QString and then it works fine.
If anyone of you has an idea, why the crash in destructing such a nested struct (another information: doesnt matter if a allocate the QVariants in heap and delete them myself or stack) and how to fix it, please let me know.

QDataStream readSlot termination symbol

at the moment My socket conversation is text based. I end all my conversation end with a ; and some conversations are binary. now I've decided to make all my conversations binary. and I want to use QDataStream as the socket wrapper. so what measures should I take in place of ; usage.
e.g. i used to check for the ; at the end. when readyRead was emitted. now I think I'll put the buffer size at the begening of the buffer. but the problem is when I get some incomplete buffer. can I parse the size ?
Neel, I'd recommend you the following: QDataStream has convenient overloaded "operator>>" and "operator<<". What I usually do in such case is define the size of the data to be, for example, first 4 bytes of the stream. And on the other end I expect those 4 bytes to be read to determine the whole data size.
For example some pseudo code (C++ style but just gives and idea what you need rather than 100% polished and working code):
QByteArray myData = getData();
QDataStream ds(&socket);
ds << myData.size();
// Note: here your data will be encoded and be '\0' terminated
ds << myData.constData();
// so you might want to consider this call
// although since Qt doesn't guarantee exactly myData.size bytes to be written
// its your responsibility to check whether everything is written
ds.writeRawData(myData.constData(), myData.size());
Now, if you use QByteArray or any of the Qt types that can be sent through QDataStream, you can take advantage of what is already implemented in Qt and send your data as simple as:
QByteArray myData = getData();
QDataStream ds(&socket);
ds << myData;
In this case just check here http://doc.qt.nokia.com/4.7/datastreamformat.html of how Qt writes QByteArray to QDataStream. Even more: if you have QDataStream on the second end, all you need to do is just read your data as easy as you wrote it.
Hope that helps.

QT: make a function to pause at some moment for some time

I've got a QT problem.
I want to make my program stop at place where I define, let`s say for 3 seconds. I couldn't manage to do that. I need that because earler my program generates file and it is used by a program which I call a bit later. Problem is, that file doesn't seem have enough time to create. My code looks like this:
void MainWindow::buttonHandler()
{
QFile ..... (creating a text file);
//Making a stream and writing something to a file
//A place where program should pause for 3 seconds
system("call another.exe"); //Calling another executable, which needs the created text file, but the file doesn`t seem to be created and fully written yet;
}
Thanks in advance.
Some possibilities:
1) Use another slot for the things to do after the sleep:
QTimer::singleShot(3000, this, SLOT(anotherSlot());
...
void MyClass::anotherSlot() {
system(...);
}
2) Without another slot, using a local event loop:
//write file
QEventLoop loop;
QTimer::singleShot(3000, &loop, SLOT(quit()) );
loop.exec();
//do more stuff
I would avoid local event loop and prefer 1) though, local event loops can cause a plethora of subtle bugs (During the loop.exec(), anything can happen).
Try void QTest::qSleep ( int ms ) or void QTest::qWait ( int ms )
Looking into the source of these functions is also useful if you do not want the overhead of QTest.
More info at http://doc.qt.io/qt-5/qtest.html#qSleep
Maybe you just need to close the written file before you call the other program:
QFile f;
...
f.close();
(This also flushes internal buffers so that they are written to disk)

Resources