QTextStream atEnd() is returning true when starting to read from a file - qt

I want to read and parse contents of the /proc/PID/status file on a linux machine, but the QTextStream.atEnd is always returning true when starting to read. The code:
QString procDirectory = "/proc/";
procDirectory.append(QString::number(PID));
procDirectory.append("/status");
QFile inputFile(procDirectory);
if (inputFile.open(QIODevice::ReadOnly))
{
QTextStream in(&inputFile);
QString line;
while (!in.atEnd())
{
line = in.readLine();
File exists and if I read lines manually without the while expression, the files are read normally.
Did I miss something obvious?
(Debian 8 x64, QT 5.4.1 x64, gcc 4.9.2)

Nevermind found out I needed to read one line before the while clause, now it works.

The preferred way oft looping over these streams is with a do/while loop. This is for allowing the stream to detect Unicode correctly before any queries (like atEnd) are made.
QTextStream stream(stdin);
QString line;
do {
line = stream.readLine();
} while (!line.isNull());

Related

How to work around string splitting while loading a list from a file in QT

I'm trying to create a simple "To Do list" app in QT Creator while coding the part that loads and saves the list from a file I get stuck on a problem.
If you enter a string like "Do my homework" the program threads the string as it should, but when you load the program again the save file got split in words. So it gets all the entries but each word separated ("Do", "my", "homework").
What is the solution? I tried working with 'char arrays' and 'getline' but they give me nothing but errors.
Here is my code for the save and load parts:
void MainWindow::LoadList(){
std::ifstream load_file("./data.bin");
char loader[255];
while (load_file >> loader){
QString Writer = QString::fromStdString(loader);
ui->lstTaskList->addItem(Writer);
}
}
void MainWindow::SaveList(){
std::ofstream save_file("./data.bin");
for (auto i = 0; i < ui->lstTaskList->count(); i++){
QString Saver = ui->lstTaskList->item(i)->text();
std::string saver = Saver.toStdString();
save_file << saver << std::endl;
}
}
Can anyone help me with this, please?
My thanks in advance...
The anwser was using QFile and QByteArray for me, I knew about QFile but it tries using basic "std" c++ till I learned more about QT.

Overwrite text file vs append

I'm looking to overwrite data in a text file but all I can seem to do is append to it
mFile.open(QFile::ReadWrite)
QTextStream in(&mFile);
QString first = in.readLine(); //discard the headers
QString dataLine = in.readLine(); //headers
QStringList sql_row = dataLine.split("\t"); //first row (sake of proj only 1 row)
if(sql_row[1].isEmpty()) //no user name registered
{
QByteArray user= getenv("USERNAME"); //for windows
if(user.isEmpty())
{
user = getenv("USER"); ///for MAc or Linux
}
dataLine = dataLine.insert(dataLine.indexOf("\t")+ 1,user);
in << first << endl << dataLine << endl;
mFile.flush();
mFile.close();
Change
mFile.open(QFile::ReadWrite);
to
mFile.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text);
The QIODevice vs QFile distinction isn't necessary, but I personally favor using the base class. The Truncate flag will overwrite (i.e., delete) an existing file.
Alternatively, you can follow the other suggestion and open your text file directly using one of QTextStream's constructors. The same QIODevice::OpenMode conventions apply. This only works if mFile is a FILE object and not a QFile, which isn't the case in your example.
A couple additional notes for beginners.
Related Note 1
You didn't ask about this, but I also added the QIODevice::Text flag to ensure that newline characters get translated to/from the local encoding (plain \n vs. \r\n) when you use endl.
A really common mistake is to use \r\n AND QIODevice::Text, which results in text files with double-returns \r\r\n on Windows. Just use QIODevice::Text when opening and simply \n or endl and you'll never have this problem.
Related Note 2
Using QTextStream::endl will automatically call flush() each time. If your loop is large, use "\n" instead to prevent a slowdown unless you actually need to flush every line. The stream will automatically write to disk as its buffer gets full, or when it's closed.
QFile::close() also calls flush(), which makes your mFile.flush() at the end redundant.
Use an overloaded constructor of QTextStream:
QTextStream in(&mFile, QIODevice::ReadWrite | QIODevice::Truncate);
The QIODevice::Truncate will remove all the previous content of the file, and QIODevice::ReadWrite will open it for read and write access.

read a text file to QStringList

I have a text file. I need to read it to a QStringList. there are no line seperators. I mean each line in the text file is in a new line. So is there anyway i can do this?
I assume that every line should be a separate string in the list. Use QTextStream::readLine() in a cycle and on each step append the returned value to the QStringList. Like this:
QStringList stringList;
QFile textFile;
//... (open the file for reading, etc.)
QTextStream textStream(&textFile);
while (true)
{
QString line = textStream.readLine();
if (line.isNull())
break;
else
stringList.append(line);
}
QFile TextFile;
//Open file for reading
QStringList SL;
while(!TextFile.atEnd())
SL.append(TextFile.readLine());
If the file isn't too big, read the whole content into a QString and then split() it into a QStringList.
I like using the QRegExp version to handle linefeed from different platforms:
QStringList sList = s.split(QRegExp("(\\r\\n)|(\\n\\r)|\\r|\\n"), QString::SkipEmptyParts);
I like my code to be fully indented/paranthesized with obvious variable names (they may take longer to type but are much easier to debug) so would do the following (but changing "myTextFile" and "myStringList" to more sensible names, such as "employeeListTextFile")
QFile myTextFile;
QStringList myStringList;
if (!myTextFile.open(QIODevice::ReadOnly))
{
QMessageBox::information(0, "Error opening file", myTextFile.errorString());
}
else
{
while(!myTextFile.atEnd())
{
myStringList.append(myTextFile.readLine());
}
myTextFile.close();
}
The below code reads the file
QFile File("/file_path");
if(!File.open(QIODevice::ReadOnly));
{
qDebug("Error");
}
QTextStream in(&File);
while(!in.atEnd())
{
qDebug()<<ReadAll;
ReadAll=in.readAll();
}
File.close();
Now the file is closed, now split the new line i.e \n here \r is carriage return
List= ReadAll.split(QRegExp("[\r\n]"),QString::SkipEmptyParts);

QDir and QDirIterator ignore files with non-ASCII filenames

The following code somehow fails to notice any files with non-ASCII characters in their names (Cyrillic characters, specifically):
for (int path = 1; path < argc; path++) {
QFileInfo fi(argv[path]);
if (fi.isDir()) {
QDir dir(argv[path], "", QDir::LocaleAware, QDir::AllEntries);
qDebug() << dir.entryList();
QDirIterator it(QString(argv[path]), QDirIterator::Subdirectories);
while (it.hasNext()) {
it.next();
qDebug() << it.fileInfo().absoluteFilePath();
/* Processing; irrelevant in the context of the question */
}
}
}
What exactly am I doing wrong here? How should I handle QDir and QDirIterator to make them aware of Cyrillic filenames?
The system locale is en_US.UTF-8.
Update: On Windows, everything works correctly.
Get cmd line parameters out of QApplication itself.
So
QApplication app(argc, argv);
QStringList args = app.arguments();
for(...)
Qt will handle encoding properly. But that will only fix problems with unicode on cmd line. Not sure if that is your main problem though.
EDIT:
fromLocal8Bit() probably doesn't work because it wasn't local encoding, but utf8. So fromUtf8() would work on linux and osx (but it won't work on windows). On *nuxes it depends on some environment variables (LS_LANG or something). I guess Qt takes everything into account and converts it properly. You can look at the constructor code for QApplication if you want to know exactly what they do.
Which part is failing? Reading the initial directory specified argv[path] or the iterator? If it's the former, you should convert byte strings to QString for file processing using QFile::decodeName. The default char* => QString conversion uses Latin-1, which is not what you want for file names.
Don't use argv[path] just like that when constructing the QStrings. This will treat the string as a latin1 string (which doesn't care about cyrillic characters). Try using
const QString dirName = QString::fromLocal8Bit( argv[path] );
at the top of your loop and then use dirName everywhere instead of argv[path].

How to get magic number of a binary file

There is a magic number associated with each binary file , does anyone know how to retrieve this information from the file?
file <file_name>
magic numbers are usually stored in (linux):
/usr/share/file/magic
also check this link, someone was trying to use libmagic to get the information in C program, might be useful if you're writing something yourself.
Use libmagic from the file package to try and sniff out the type of file if that's your goal.
There are no general "magic" numbers in binary files on unix, though different formats might define their own. The above library knows about many of those and also use various other heuristics to try and figure out the format/type of file.
The unix file command uses magic number. see the file man page for more.(and where to find the magic file )
Read this: http://linux.die.net/man/5/magic
It's complex, and depends on the specific file type you're looking for.
There is a file command which in turn uses a magic library, the magic library reads from a file found in /etc called magic (this is installation dependant and may vary), which details what are the first few bytes of the file and tells the file what kind of a file it is, be it, jpg, binary, text, shell script. There is an old version of libmagic found on sourceforge. Incidentally, there is a related answer to this here.
Hope this helps,
Best regards,
Tom.
Expounding on #nos's answer:
Example below uses the default magic database to query the file passed on the command line. (Essentially an implementation of the file command. See man libmagic for more details/functions.
#include <iostream>
#include <magic.h>
#include <cassert>
int main(int argc, char **argv) {
if (argc == 1) {
std::cerr << "Usage " << argv[0] << " [filename]" << std::endl;
return -1;
}
const char * fname = argv[1];
magic_t cookie = magic_open(0);
assert (cookie !=nullptr);
int rc = magic_load(cookie, nullptr);
assert(rc == 0);
auto f= magic_file(cookie, fname);
if (f ==nullptr) {
std::cerr << magic_error(cookie) << std::endl;
} else {
std::cout << fname << ' ' << f << std::endl;
}
}

Resources