Qt c++ QFile writes only last input [duplicate] - qt

This question already has an answer here:
Open QFile for appending
(1 answer)
Closed 6 years ago.
I have a function saveResolvedInfo() that should save each resolved ip address from structure _ResolvedInfo to an ip.txt file:
void saveResolvedInfo()
{
_ResolvedInfo rf;
QFile file("ip.txt");
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out << rf.country << " " << rf.ip << "/n";
}
Well, it only writes last resolved ip address. Any ideas whats wrong with my code?

Each call kills the previous content, so you are only seeing the result of the last one.
This happens because by default when you open a QFile specifying QIODevice::WriteOnly the existing data is destroyed, as explained in the documentation:
QIODevice::WriteOnly The device is open for writing. Note that this mode implies Truncate.
QIODevice::Truncate If possible, the device is truncated before it is opened. All earlier contents of the device are lost.
If you want to keep the existing file content, you have to pass the QIODevice::Append flag.
QIODevice::Append The device is opened in append mode so that all data is written to the end of the file.
file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);

Related

Writing Issues With QTextStream

QFile vfile(file);
if(!vfile.open(QIODevice::ReadWrite | QIODevice::Text)) qDebug() << "FILE COULDN NOT BE OPENED";
QTextStream stream(&vfile);
stream << "Hello" << "=";
vfile.write("132");
Output to File - 132Hello=
In the above example, I write the data in 2 different ways but when I see the file I found some this type of result that while using "write()" the data within write() printed first instead of the above statements is displayed in the example.
The stream data is cached for a time (which is typical of writing to streams in general, eg. stdout and such). You can flush the stream data to be sure it is all written before writing to the file via a different method.
stream << "Hello=" << flush;
vfile.write("123");
Also see manipulator functions list in https://doc.qt.io/qt-5/qtextstream.html#details
Writing an end-of-line character (endln or \n) will also flush the stream buffer.

With Qt, how to check if stdin is empty?

I have a Qt program that processes stdin data like this:
QTextStream qtin(stdin);
QString stdindata = qtin.readAll();
QByteArray ba;
ba = stdindata.toUtf8();
QJsonDocument exJSONDoc(QJsonDocument::fromJson(ba));
QJsonObject extRoot;
extRoot = exJSONDoc.object();
QStringList keys;
keys = extRoot.keys();
for (int n=0; n <= keys.count()-1; n++)
{
qDebug() << extRoot.value(keys[n]).toString();
}
It works when I call my program like this:
myprogram < ./data.json
But if I call it without any "<" it hangs in qtin.readAll().
How can I check with Qt if the stdin is empty?
(I am assuming a Linux -or at least POSIX- operating system)
QTextStream qtin(stdin);
QString stdindata = qtin.readAll();
This would read stdin till end-of-file is reached. So works with a redirected input like
myprogram < ./data.json
But if I call it without any "<" it hangs ...
But then (that is, if you run myprogram alone) stdin is not empty. It is the same as your shell's stdin. and your program, being the foreground job, is waiting for input on the terminal you are typing (see also tty(4)). Try (in that case) typing some input on the terminal (which you could end with Ctrl D to make an end-of-file condition). Read about job control and the tty demystified and see also termios(3).
Perhaps you could detect that situation with e.g. isatty(3) on STDIN_FILENO. But that won't detect a pipe(7) like
tail -55 somefile | myprogram
You need to define what an empty stdin is for you. I have no idea what that means to you, and I would instead think of myprogram < /dev/null (see null(4)) as the way to get an empty stdin.
Perhaps you should design myprogram so that some program
option (perhaps --ignore-stdin) is avoiding any read from stdin.
Problem here is readAll. See documentation:
Reads the entire content of the stream, and returns it as a QString.
Avoid this function when working on large files, as it will consume a
significant amount of memory.
So it reads stdin until it encounters end of file and since stdin is associated with console you have to signal end of file. Usually it is Ctrl-D and press enter.
It is more probable you what to read stdin line by line.
To alow user text editing console transfers data to standard input of the application only line by line. This was designed like this ages ago when computer had only a printer as user interface (no screen).
Now question is how to read JSon form stdin console connected with console without end of file information?
I would use some SAX parser, but this would be to complicated for you.
So is there another way to detect end of JSon?
You can try this approach (this is basic idea, not final solution, so it has couple shortcomings):
QFile file(stdin);
QByteArray data = file.peak(largeNumber);
QJsonParseError error;
QJSonDocument doc = QJSonDocument::fromJson(data, &error);
while (!doc.isValid() && JSonNotTerminatedError(error.error))
{
// TODO: wait for new data - it would be best to use readyRead signal
doc = QJSonDocument::fromJson(data, &error);
}
Where JSonNotTerminatedError returns true for respective QJsonParseError::ParseError values (see linked documentation) which are related with unterminated JSon data.
Now I see QFile doesn't have required constructor, but main concept should be clear. Read data from stdin and check if it is a valid JSon document.

Qt's QDir: File Names Dropping Non-Ascii Characters

I am having issues with QDir losing Non-Ascii characters from my file names.
I have files with names like testingöäüß.txt or exampleΦ.shp and when trying to use Qt utilities like QDir and QFile they simply show up as testing.txt and example.shp. Seems as though I cannot tell those classes what kind of encoding to use. I'm trying QDirIterator and the QDir function entryInfoList:
QDir someDir("/home/blah"); //contains testingöäüß.txt
QDirIterator dirIter(someDir.absolutePath(), QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files);
while(dirIter.hasNext())
{
QString fileName1 = QFile::decodeName(dirIter.next().toUtf8());
std::cout << "QDirIterator Name " << fileName1.toStdString().c_str() << std::endl;
}
QFileInfoList fileInfoList = someDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files);
foreach(QFileInfo fileInfo, fileInfoList)
{
QString fileName1 = QFile::decodeName(fileInfo.fileName().toUtf8());
std::cout << "entryInfoList Name " << fileName1.toStdString().c_str() << std::endl;
QString fileName2 = QFile::decodeName(fileInfo.absoluteFilePath().toUtf8());
std::cout << "entryInfoList Name2 " << fileName2.toStdString().c_str() << std::endl;
QString fileName3 = QString::fromUtf8(dirIter.fileInfo().absoluteFilePath().toStdString().c_str());
std::cout << "entryInfoList Name3 " << fileName3.toStdString().c_str() << std::endl;
}
Every one of those prints will lack the non-ascii characters. Seems like as soon as you try to grab the file names to loop over they will be ascii only. Anyone have any ideas on this? Or can Qt simply not handle this? Thanks!
I know this is an old question, but I just ran into the same problem. The same exact Qt code would work fine on my development VM, but when I transferred it to an embedded Linux system (running on x86 so literally the same executable) my directory names just silently got their non-ASCII characters dropped.
Turned out the QTextCodec::codecForLocale on my dev VM was set to UTF-8, and on the embedded box it was System. If I manually changed the locale to UTF-8 before doing any filesystem operations (by calling QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"))), everything started working fine.
So why was this happening in the first place? My suspicion is that in the process of slimming down the embedded system's root filesystem I might have accidentally deleted some locale-related files that Qt was using to try to auto-detect the locale. When it couldn't determine it was on UTF-8, it fell back to System, which for whatever reason is broken (maybe for the same reason it couldn't detect UTF-8 in the first place).
I need to eventually fix whatever is causing it to not auto-detect, but in the short-term just manually setting a UTF-8 locale should work if you are experiencing this same issue.
Note that this has nothing to do with whether the console can display UTF-8, or anything to do with manual conversion of UTF-16 to UTF-8! So Felix's answer to this question is not correct, at least for this particular issue. To completely remove the capability of the console from the equation, I was also simply printing the number of UTF-16 characters in the string, and every non-ASCII character actually made the returned path and filename strings from QDir::entryInfoList have one less UTF-16 character. Additionally, the dead giveaway is that the characters were simply stripped out, not just replaced with garbage or question marks or whatever.
Qt can handle filenames with special characters. You just make them disappear somewhere in that string conversion stuff. (Which is completly unnecessary) Try it this way:
#include <QDebug>
//...
QFileInfoList fileInfoList = someDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files);
foreach(QFileInfo fileInfo, fileInfoList)
{
qDebug() << fileInfo.fileName();//uses qdebug
std::cout << fileInfo.fileName().toStdWString() << std::endl;//uses a 16Bit string on normal cout
}
If you still don't see them, it's because your console settings do not allow to display them. Try to write them to a file or display them in a gui - or simply try to open a file with that name, it will work.

QSettings INI file: value containing semicolon

I'm trying to read and edit a Desktop Entry .desktop file using Qt QSettings. The problem is that these files contain keys with multiple values separated by semicolon ;. I tried reading these as QStringList but no luck. I only get the first value. For example:
Keywords=disc;cdrom;dvd;burn;audio;video;
Categories=GTK;GNOME;AudioVideo;Audio;Video;DiscBurning;
MimeType=application/x-cd-image;application/x-cdrdao-toc;application/x-cue;application/x-toc;audio/x-scpls;audio/x-ms-asx;audio/x-mp3-playlist;audio/x-mpegurl;application/x-brasero;x-content/audio-cdda;x-content/video-dvd;x-content/video-vcd;x-content/video-svcd;x-content/image-picturecd;
Getting the values with:
settings.value("Desktop Entry/MimeType").toStringList();
settings.value("Desktop Entry/MimeType").toString();
returns only the first value (in my example: disc, GTK or application/x-cd-image).
How to I return the full value from those keys? And how do I write it back using QSettings?
Update (first attempt was completely useless)
Variant 1
QMap<QString, QString> settings;
QFile inFile("<input filename.ini>");
if(inFile.open(QIODevice::ReadOnly))
{
QTextStream in(&inFile);
while (!in.atEnd())
{
QString line = in.readLine();
QStringList linelist = line.split("=");
settings[linelist[0]] = linelist[1];
}
}
Variant 2
use QSettings::registerFormat().
This is probably the only "clean" way to do it with QSettings. The advantage is that you can register it with the .desktop extension. You'll have to write a pair of ReadFunc() and WriteFunc() functions.
I think you can't do it. QSettings has certain interpretation of .ini file format, which is very close to Windows interpretation, and is not meant for generic parsing. Semicolon starts a comment, and apparently QSettings allows comment after value until end of line, and AFAIK there's no way around it.
You need to find a different library to handle .desktop files, or implement one yourself.

How to save a QPixmap Object to a file?

I'm having trouble reading and writing QByteArray data to a file.
My goal is to save QPixmap data into a QByteArray and save that QByteArray to a file (with the ability to read this QByteArray back from the file and into a QPixmap). I want to use following code from the QPixmap documentation:
QPixmap pixmap(<image path>);
QByteArray bytes;
QBuffer buffer(&bytes);
buffer.open(QIODevice::WriteOnly);
pixmap.save(&buffer, "PNG"); // writes pixmap into bytes in PNG format
After writing the buffer to a file, I want to be able to retrieve the QByteArray and load it back into a QPixmap using the QPixmap::loadFromData() function.
Please let me know if any further clarification is needed (I'm open to alternative approaches as well, I just need to be able to read and write the QPixmap to a file! :) );
That seemed like a really long way to go about doing it (but your comment better explains):
For writing:
QFile file("yourFile.png");
file.open(QIODevice::WriteOnly);
pixmap.save(&file, "PNG");
For reading:
QPixmap pixmap;
pixmap.load("yourFile.png");
QBuffer is great when you need a QIODevice and want to keep it in memory, but if you're actually going out to disk, then it's an unnecessary middle step.
EDIT:
To write pixmaps, and other things, to a single file I'd recommend that you use QDataStream.
For writing:
QFile file("outfile.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out << QString("almost any qt value object")
<< yourQPixMap << yourQList /* << etc. */;
Then, you can do similarly for reading:
QFile file("infile.dat");
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
in >> firstQString >> yourQPixmap >> yourList /* >> etc. */;
You'll need to make sure that you read in the same objects as you wrote them out. In order to save yourself future compatibility headaches, set the QDataStream version explicitly.

Resources