Converting valid QFile to QString - QString is empty - c++

So I am trying to convert a QFile into a QString by doing the following:
void MainWindow::openTemplateFile(QString location)
{
if (location.isEmpty())
return;
else
{
QString variable;
templateFile.setFileName(location);
if (!templateFile.open(QFile::ReadOnly | QFile::Text))
{
QMessageBox::information(this, "Unable to open template",
templateFile.errorString());
return;
}
else // file opened and ready to read from
{
QTextStream in(&templateFile);
QString fileText = in.readAll();
qDebug() << templateFile.size() << in.readAll();
}
}
}
However, in I get the following result in the debug console:
48 ""
templateFile does exist and is part of the MainWindow class. This is also simplified code - in the actual program I read chars from the file and it works correctly. The location string is a result of the QFileDialog::getOpenFileName function, which I open a txt file with.

You call readAll() twice. The second time, the stream is positioned at end-of-file, and so readAll() has nothing to read and returns an empty string. Print fileText in your debug output instead.

Related

Infinite cycle due to QTextStream

So, I get infinite cycle while trying to read lines from file (line by line). I was trying to use do{}while(); cycle like that:
QTextStream stream(stdin);
QString line;
do {
line = stream.readLine();
} while (!line.isNull());
but I get empty string.
Sure, I checked file path (it is right). I was trying to use /Users/user/tts.txt path but without changes. I was trying to read other files (like m3u). And it's not working on macOS Catalina, Windows 10, Linux (Debian).
So, why did I get infinite cycle?
QStringList Manager::GetLinesFromFile(const QString &nameOfFile)
{
QStringList lines = {};
//path to file
const QString path = QCoreApplication::applicationDirPath() + "/bin/" + "tts.txt";
//"/Users/user/tts.txt"
QFile buffer;
buffer.QFile::setFileName(path);
#ifndef Q_DEBUG
qDebug() << path;
#endif
if(buffer.QFile::exists())
{
if(!buffer.QIODevice::open(QIODevice::ReadOnly))
{
#ifndef Q_DEBUG
qCritical() << "error: can't open file";
#endif
}
else
{
QTextStream stream(&buffer);
// both conditions
// (!stream.QTextStream::atEnd())
while(!buffer.QFileDevice::atEnd())
lines.QList::push_back(stream.QTextStream::readLine());
buffer.QFile::close();
}
}
else
{
#ifndef Q_DEBUG
qCritical() << "error: file not exists";
#endif
}
return lines;
}
Have a look at the QTextstream documentation https://doc.qt.io/qt-5/qtextstream.html. There is an example of reading line by line. Your while loop should read until the stream reaches the end of the buffer and many of the in built read functions will return false when his happens
So, I got it. I opened the file incorrectly.
I was using:
if(!file.QIODevice::open(QIODevice::ReadOnly))
but it should be like that:
if(!file.QFile::open(QFile::ReadOnly))

Is it necessary to flush a QTextStream before closing a QFile?

I need to log some text messages to a file with following requirements :
Each text messages is written in a new line at the end of the file.
Be reasonably sure that each message was correctly written to the file.
So far, the function is using QTextStream and QFile:
bool FileManager::appendLine(const QString &line)
{
if(!m_file.open(QIODevice::Append | QIODevice::Text)) // m_file is a QFile
return false;
QTextStream ts(&m_file);
ts << line << endl;
bool status = (ts.status() == QTextStream::Ok);
m_file.close();
return status;
}
Point 1 is satisfied but i have doubts about Point 2.
Even Qt Doc says that it is sufficient to close() the QFile to flush all its internal buffers :
void QFileDevice::close()
Reimplemented from QIODevice::close().
Calls QFileDevice::flush() and closes the file. Errors from flush are ignored.
What about the internal buffer of the QTextStream ?
Is it necessary to call QTextStream::flush() before closing the file ?
About Point 2, i guess that reading back the line just after it has been written would be the only way to be 100% sure of that. (for example a power failure may occur while the kernel has still datas in its buffers )
Thanks.
In your case, its not, because you are appending &endl in each write!
Writting &endl to the QTextStream writes '\n' to the stream and flushes the stream. It is Equivalent to: stream << '\n' << flush;
Further, when QTextStream is flushed due to &endl, it will empty all data from its write buffer into the device and call flush() on the device.
While this particular code will work because operations with QTextStream end with an endl, it's still better to ensure that QTextStream is completely and utterly finished working with the file when you close it. Just use scopes.
bool FileManager::appendLine(const QString &line)
{
if(!m_file.open(QIODevice::Append | QIODevice::Text)) // m_file is a QFile
return false;
bool status {false};
{
QTextStream ts(&m_file);
ts << line << endl;
status = (ts.status() == QTextStream::Ok);
}
m_file.close();
return status;
}

Qt Creator combobox

How to write Combobox current text in a preexisting text file in hard drive? Here is my code:
void second::on_pushButton_4_clicked()
{
QFile file("vik.txt");
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
out << ui->comboBox_5->currentText() << "\n";
}
Maybe you forgot to close the file
void second::on_pushButton_4_clicked()
{
// Get comboBox text value
QString txt = ui->comboBox_5->currentText();
// Open file for writing
QFile file("vik.txt");
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
// Write in file
out << txt << "\n";
// Close file
file.close();
}
You have several issues in your code, let me enumerate them one-by-one:
You need this flag for "overwrite" as per your comment:
QIODevice::Truncate 0x0008 If possible, the device is truncated before it is opened. All earlier contents of the device are lost.
More importantly, have you checked whether the method returns after open with some error? If it does, please print out file.errorString() there:
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << file.errorString();
return;
}
On the most important note, you are likely facing the issue that the file is not in your current working directory. If the file resides beside the application executable, please change the corresponding line into your code to this:
QFile file(QCoreApplication::applicationDirPath() + "/vik.txt");

Qt getting network requests with QNetworkReply that download data to temp file

I am having some issues reading an online file. I'm trying to read what is in the file after it gets downloaded to a temporary file. Here is my code:
void MainWindow::fileIsReady( QNetworkReply * reply)
{
QTemporaryFile tmpFile;
tmpFile.write(reply->readAll());
QByteArray asdf = reply->readAll();
qDebug() (QString("%1").arg(asdf.length())); // returns 0
if (tmpFile.open())
{
qDebug << "attempting to read file";
QTextStream stream(&tmpFile);
QString value = stream.readAll();
qDebug << value; // value is returning nothing
}
else
{
qDebug() << "failed to open internet file";
}
}
// in MainWindow constructor (MainWindow::MainWindow)...
QNetworkAccessManager * manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(fileIsReady(QNetworkReply*)) );
manager->get(QNetworkRequest(QUrl("https://www.website.com/stuff/file.exe.md5")));
I'm going to be using this to compare two md5 strings.
There are several issues in your code:
You need to open tmpFile before writing to it.
reply->readAll() will return data only once. Further calls will return empty array. Once you received data using readAll, it's your responsibility to store it in a variable if you need it later.
After you wrote someting to file, the file pointer is at its end. You cannot read anything from it because there is no data there. You can use seek to move pointer to the beginning of the file and read its content.
There is no point in reading from file just after you wrote data to it. You can use QTextStream on QNetworkReply directly to read text from it. (Maybe this was just for debugging, I don't know.)
It's hard to believe that you need to create a temporary file just to calculate md5. There are simplier ways to do that.
So turns out I was dumb and forgot to open the reply first. Also, it was unnecessary for me to create a temp file. Here is my solution::
void MainWindow::fileIsReady( QNetworkReply * reply)
{
if (reply->error() == QNetworkReply::NoError)
{
if (reply->open(QIODevice::ReadOnly))
{
QByteArray asdf = reply->readAll();
qDebug() << (QString("asdf %1").arg(asdf.length()));
qDebug() << (QString(asdf));
}
else
{
qDebug << "cant open reply";
}
}
}

Using QTextStream to read a file that is being written to?

I currently read data from a file line by line like so
readFile(QFile *file)
{
QTextStream in(file);
while(!in.atEnd())
{
// Do stuff
}
}
I need to extend this to handle files that are currently being written to. The while loop should only exit if nothing has been written to the file for N seconds.
This should be easily implemented by adding in a timer and a sleep/wait loop, continuously checking if we are still atEnd(). However, the documentation is not very clear whether the return value of atEnd() will change if new data has been appended to the file.
If I use a QTextStream to read from a file that is being written to, will the return value of atEnd() accurately reflect the change in file contents?
will the return value of atEnd() accurately reflect the change in file contents?
Yes
You can test this by executing the following function:
void FileReader::_appendFileTest()
{
QFile file("/home/cklein/appendFile");
file.open(QIODevice::ReadOnly);
QTextStream in(&file);
while(true)
{
while(!in.atEnd())
{
QString line = in.readLine();
qDebug() << line;
}
SleepThread::msleep(1000);
}
}
Code for SleepThread taken from here. It just exposes the protected QThread::msleep() function.
And while the application is running, type this in the terminal
~ $ echo "foo" >> appendFile
~ $ echo "bar" >> appendFile
You can see that without resetting or re-opening the file, the atEnd() function returns a false when the file is appended to.