How to recursively write data to a text file in C++/ Qt - c++

I have a C++\Qt program that scans the files in a particular directory. I'm trying to write the paths to the files contained therein in a text file, but all I've managed to do is write the path to the last file.
void ScanDir::qDirIteratorScanner(QString path)
{
QDirIterator it(path, QStringList() << "*.mp4", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext())
{
WriteToFile writeToFile(path, it.next());
qDebug() << "it.next()";
}
}
...
WriteToFile::WriteToFile(QString path, QString data)
{
path += "/Data.txt";
QFile file(path);
if (file.open(QFile::ReadWrite)) {
QTextStream stream(&file);
stream << data << endl;
}
}
How can I write all the paths into the text file?

You're creating a QFile in read/write mode at each call of WriteToFile: this is truncating the contents of the file, so only contents written by the last call will remain.
Try:
void ScanDir::qDirIteratorScanner(QString path)
{
QDir dir(path);
QFile file(dir.absoluteFilePath("Data.txt"));
if (file.open(QFile::ReadWrite)) {
QTextStream stream(&file);
QDirIterator it(
dir,
QStringList() << "*.mp4",
QDir::Files,
QDirIterator::Subdirectories
);
while (it.hasNext())
{
stream << it.next() << endl;
}
}
}
Here the file is opened only once. If you want/need to keep a function WriteToFile, pass stream as an additional parameter (by reference).
Note:
As proposed by Simon Kraemer in the comments, I used QDir::absoluteFilePath as it makes it easier to prevent missing or accidental slashes in the path.
An alternative to keep your design may be to use QFile::Append mode:
void ScanDir::qDirIteratorScanner(QString path)
{
QDir dir(path);
// reset the file
{
QFile file(dir.absoluteFilePath("Data.txt"));
file.open(QFile::ReadWrite);
}
QDirIterator it(
dir,
QStringList() << "*.mp4",
QDir::Files,
QDirIterator::Subdirectories
);
while (it.hasNext())
{
WriteToFile writeToFile(path, it.next());
qDebug() << "it.next()";
}
}
WriteToFile::WriteToFile(QString path, QString data)
{
QDir dir(path);
QFile file(dir.absoluteFilePath("Data.txt"));
if (file.open(QFile::Append)) {
QTextStream stream(&file);
stream << data << endl;
}
}

Each time you open the file and write one line to it, overwriting whatever is in the file. Instead, try opening it in append mode, this should cause whatever you write to be added at the end of the file.
QTextStream stream(&file,QIODevice::Append);

You must open the file in "append" mode, otherwise you will override its content every time you open the file:
file.open(QFile::Append)
2 remarks to your code:
Writing to a file from a constructor seems questionable. Why don't you just declare a function?
Why don't you open the file just once?
void ScanDir::qDirIteratorScanner(QString path)
{
QFile file(QDir(path).absoluteFilePath("Data.txt"));
if(file.open(QFile::WriteOnly))
{
QTextStream stream(&file);
QDirIterator it(path, QStringList() << "*.mp4", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext())
{
stream << it.next() << endl;
qDebug() << "it.next()";
}
}
}

It would be most efficient to move the file opening and writing to qDirIteratorScanner() instead of WriteToFile(). This way you can open the file, write everything, then close the file.
What you have now is you keep on opening (and overwriting) the same file on every iteration. That's why you are only left with the last write. Alternatively, you could open the file with the QIODevice::Append flag, but that's just unnecessary operations compared to the first suggestion, where you will open the file only once to write everything.

Related

Converting valid QFile to QString - QString is empty

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.

Qt5: How to read/write the file in local file system

I'm new to Qt.In my app,I want to press a button and it will come out a QFileDialog to let me select the file in file system .So how to do that?
After that , here is my problem, I don't know which API in Qt works just like "open" in POSIX ? I think if I can open the file in the right way , this API will return me a file descriptor and I can read/write this file like open did in posix.
I read some documents and found some classes such as QFile QDataStream but I don't know if they are exactly what I want.
Those are exactly what you are looking for.
In particular, you can use some of the static methods of QFileDialog to get a reference to the file you want to open, like:
static QString getOpenFileName(QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString(), QString * selectedFilter = 0, Options options = 0)
and then use a QFile and QDataStream or QTextStream to read the contents.
You'd use QDataStream for reading binary data most of the times, like follows:
QFile f(fileName);
if (f.open(QIODevice::ReadOnly)) {
QDataStream stream(&f);
int data;
stream >> data;
}
Otherwise you can read plain text with QTextStream as follows:
QTextStream stream(&f);
QString line;
do {
line = stream.readLine();
/* do something with the line */
} while (!line.isNull());
Qt docs are pretty complete, you just have to take your time and read them. There's also plenty of examples.
Only Reading:
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open file"), "", tr("all Files ()"));
QFile file(fileName);
if(file.open(QIODevice::ReadOnly)){
QByteArray arr = file.readAll();
file.close();
}
Only Writing:
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open file"), "", tr("all Files ()"));
QFile file(fileName);
if(file.open(QIODevice::WriteOnly)){
file.write(QBtyeArray("Heelo World"));
file.close();
}
Read and Write:
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open file"), "", tr("all Files ()"));
QFile file(fileName);
if(file.open(QIODevice::ReadWrite)){
QByteArray arr = file.readAll();
arr += " From Earth";
file.write(arr);
file.close();
}
if you use QDatastream you do not need resolve how many part you have written before,follow Below Code and I always use this method;
QBuffer buffer;
buffer.open(QIODevice::WriteOnly);
QDatastream out(&buffer);
out << QString("Hello World QString");
out << QByteArray("Hello World QByteArray");
out << int(55);
buffer.close();
QFile file(fileName);
if(file.open(QIIDevice::WriteOnly)){
file.write(buffer.data());
file.close();
}
and reading this file
QFile file(fileName);
if(file.open(QIIDevice::WriteOnly)){
QDatastream in(&file);
QString str;
QByteArray arr;
int integer;
in >> str;
in >> arr;
in >> integer;
file.close();
}
str is "Hello World QString";
arr is "Hello World QByteArray";
integer is 55;
QDataStream is adding extra bytes to file for your parts and if you read it with QDataStream, QDataStream solve how many parts and each part bytes instead of you.

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

how to write to multiple files one after another in qt?

my program needs to write to multiple files one after the other stored in folder... i hav used foreach statement to open a files ... bt when i am trying to write to it... its nt working...
my code for writing files is..
QString path = ui->pathBox->text();
QDir mydir(path);
QStringList filter("*.txt");
foreach (QString filename,mydir.entryList(filter,QDir::Files))
{
QFile ofil(filename);
if(!ofil.open(QIODevice::Append | QIODevice::Text))
{
qDebug() << "The file could not opened";
return;
}
QTextStream ostream(&ofil);
QString name = ui->nameBox->text();
ostream << name;
ofil.flush();
ofil.close();
}
plz tell me the correct way to write it????

QFile and QTextStream for a logger class

I'm trying to create a Logger class using QFile and QTextStream but I can't find an efficient way of doing it. I just want to create a log(...) function in it.
I know it works if I do the following:
void CLogger::log(QString strLog,int nType) {
QFile file(m_strFileName);
file.open( QIODevice::Append | QIODevice::Text );
QTextStream logStream(&file);
logStream << nType << "-" << strLog;
file.close();
}
But It is quite nasty. I don't want to create a QFile object at every log line I insert.
So from that, I tried several different ways like:
1) (with QFile *m_pFile as member)
CLogger::CLogger()
{
m_pFile = new QFile(m_strFileName);
}
void CLogger::log(QString strLog,int nType)
{
m_pFile->open( QIODevice::Append | QIODevice::Text );
QTextStream logStream(m_pFile);
logStream << nType << "-" << strLog;
m_pFile.close();
}
or
2) (with QFile *m_pFile and QTextStream *m_pLogStream as members)
CLogger::CLogger()
{
m_pFile = new QFile(m_strFileName);
m_pFile->open( QIODevice::Append | QIODevice::Text );
m_pLogStream = new QTextStream(m_pFile);
}
void CLogger::log(QString strLog,int nType)
{
*m_pLogStream << nType << "-" << strLog;
}
In the first case, I get:
C2248: 'QTextStream::QTextStream' : cannot access private member
declared in class 'QTextStream'
in the 2nd, *m_pLogStream is not equivalent to a QTextStream&.
What am I doing wrong?
Actually it is not such a bad solution to open (and close) the log file every time you need to log something (unless you log 1000 times every second... but then noone would be able to process that amount of data ...). This not only allows you to have a very stable log (since you do not keep the file open all the time, so you are no depending on the flushing of the oeprating system), but also would allow you to be able to implement features as log rolling, and other niceties.
If you keep the log file open, in case of an unwanted "crash" you might not get all the log lines, depending of course how your OS is handling this ungraceful exits.
Here is a piece of code we use for logging:
QMutexLocker locker(&m_lineLoggerMutex);
QFile f(getLogFileName());
doRollLogsIfNeeded(static_cast<qint64>(f.size() + lineToBelogged.length()));
// Do not open in append mode but seek() to avoid warning for unseekable
// devices, note that if open is made with WriteOnly without Append, the
// file gets truncated
if (!f.open(QIODevice::ReadWrite | QIODevice::Text))
{
QTextStream out(stdout);
out << "CANNOT OPEN LOG FILE: " << getLogFileName();
return;
}
// seek() does nothing on sequential devices, this is in essence what QFile
// does when Append flag is set in open() but without warning (on Qt 4.8.3)
// However, Qt 4.8.1 issues the warning, so check it explicitly
if (!f.isSequential())
{
f.seek(f.size());
}
QTextStream out(&f);
out << lineToBelogged;
This goes in a method, and the destructors take care of the closing of the devices.