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

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.

Related

Qt print document to PDF

I cannot print a QTextDocument to pdf. What I basically want is to print a table of data as a cell into a pdf file. The program runs on a virtual windows server. So I tried this:
Q_INVOKABLE QString ScriptCallback::htmlToPdf(const QString& sHtml) {
qDebug() << "Html To Pdf";
QPdfWriter pdfWriter("c:\\test.pdf");
pdfWriter.setPageSize(QPagedPaintDevice::A4);
pdfWriter.setPageMargins(QMargins(30, 30, 30, 30));
QTextDocument document;
document.setHtml(sHtml);
document.print(&pdfWriter);
QString s = "";
return s;
}
In fact instead of printing to the testfile I want to print to a QBuffer -> QByteArray. But this one above is for testing.
The problem is, I always get the error
QPainter::begin() failed
In Debug Mode the program continues, but in release the program even crashes trying to run the command
document.print(&pdfWriter);
I don't care about using QTextdocument or QPdfWriter. The only thing I am interessted in, is taking a bunch of data and somehow generate a table in a pdf file.
By the way the program runs as a console app (QCoreApplication). But I included gui and printsupport modules. So any alternatives are welcome as well.

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 c++ QFile writes only last input [duplicate]

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);

QT Can not write to a unicode file unicode strings

I am using QT Creator, created a console app. Everything is up to date. OS is Windows XP.
I have created a QString that holds some Hungarian chars. Most of the Hungarian chars do not require unicode but the chars that have double slashes for accents require unicode.
I try to write the QString contents to a file but my unicode chars lose their accents in the file. In other words, the unicode info is lost along the way.
My code is bellow.
#include <QtCore/QCoreApplication>
#include <QString>
#include <QTextStream>
#include <QDate>
#include <QFile>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QString szqLine = "NON-UnicodeIsOK: áéüúöóí NEED-Unicode: űő";
//These are Hungarian chars and require unicode. Actually, only the u & o, each having double
//slashes for eccents require unicode encoding.
//Open file for writing unicode chars to.
QFile file("out.txt");
if ( !file.open(QIODevice::WriteOnly | QIODevice::Text) ){
return 1;
}
//Stream the QString text to the file.
QTextStream out(&file);
out.setCodec("UTF-8");
out << szqLine << endl; //Use endl for flush. Does not properly write ű and ő chars.
//Accents missing in file.
file.close(); //Done with file.
return app.exec();
}
What is the encoding of your file? Using non-ascii encodings in source files often causes problems, at least when working cross-platform. I think MSVC has some problems there.
QString foo = "unicode string" uses the implicit conversion from ascii to unicode, which will also cause problems. Always explicitely specify what encoding the literal uses, e.g. by wrapping the literal using QLatin1String() if it's latin1:
QString foo = QLatin1String("some latin1 string");
or, utf-8, as it should be in your case, QString::fromUtf8():
QString foo = QString::fromUtf8( "funny characters" );
Before writing the string to a file (which is another source for possible errors, although your code looks correct), check if a qt widget (QLineEdit, for example) displays it correctly.
To avoid such errors, I prefer to keep source files pure ascii, with english strings, and then translate them using Qt's internationalization tools.
Edit: Also see the accepted answer to this question about UTF-8 literals in MSVC 2008.
Are you sure that szqLine really contains the correct characters?
Try this: QString line = QString::fromStdWString(L"NON-UnicodeIsOK: \x00E1\x00E9... NEED-Unicode: \x+0171\x0151";
... and don't use Hungarian notation ;-)

Resources