QFile error : device not open - qt

I have a code:
int actualSize = 8;
QFile tableFile("C:\\Users\\Ms\\Documents\\L3\\table"+QString::number(actualSize)+".txt");
QTextStream in(&tableFile);
QString oneLine;
oneLine.append(in.readAll());
if(tableFile.exists())
{
messageLabel->setText(oneLine);
}else
{
messageLabel->setText("Not open");
}
In the C:\Users\Ms\Documents\L3\ folder, I have a "table8.txt" file. But the messageLabel (which is a QLabel) will have a "Not open" text, oneLine is empty, tableFile.exists() is false, and I got a device not open warning/error.
I tried relative path, like
QFile tableFile("table"+QString::number(actualSize)+".txt");
But none of the methods I come up with was good.

You should be able to use / separators for all QFile-related paths. Open the file before you read it and close it when done.
int actualSize = 8;
QFile tableFile("C:/Users/Ms/Documents/L3/table"+QString::number(actualSize)+".txt");
if(tableFile.exists() && tableFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream in(&tableFile);
QString oneLine;
oneLine.append(in.readAll());
messageLabel->setText(oneLine);
tableFile.close();
} else
{
messageLabel->setText("Not open");
}

Related

Access to .h and .cpp files

I am trying to access .h and .cpp files in a selected folder. My goal is to find and print on MainWindow how many lines in .h and .cpp files. In my code, there is no problem to access to selected folder. But for example, what if a .txt file is in this folder, I do not want to count lines of .txt file. My code is here:
int countLine::funcCountLines(QString fullPath)
{
int counter = 0;
QFile file(fullPath);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
return 0;
}
while(!file.atEnd())
{
QByteArray line = file.readLine();
counter++;
}
return counter;
}
Best regards!
You can use QDir::setNameFilters to retrieve only the files you are interested in.
QDir dir;
dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
// Only find .h and .cpp files
QStringList filters;
filters << "*.cpp" << "*.h";
dir.setNameFilters(filters);
QFileInfoList list = dir.entryInfoList();
for (int i = 0; i < list.size(); ++i) {
QFileInfo fileInfo = list.at(i);
funcCountLines(fileInfo.fileName());
}

QDataStream not working as expected

I am storing some data in QDataStream and immediately taking the data, but the count is showing zero while retriving. code looks fine but unexpected behaviour
//Overloading
QDataStream& operator<< (QDataStream& writeTO, const CascadeJobInfo& data)
{
writeTO << data.m_infoJobType << data.m_connectionName << data.m_submitJobId << data.m_submitJobStat;
return writeTO;
}
QDataStream& operator>> (QDataStream& readIn, CascadeJobInfo& data)
{
readIn >> data.m_infoJobType >> data.m_connectionName >> data.m_submitJobId >> data.m_submitJobStat;
return readIn;
}
void Fun()
{
// Code Starts here
projectFileName = /*Path to folder*/
QFile file(projectFileName);
file.open(QFile::ReadWrite);
file.close();
QDataStream dStream(&file);
int jobLstCount = /*Get the Count, assume 4*/
dStream << jobLstCount;
for(int i = 0; i < jobLstCount; i++)
{
JobInfo.m_infoJobType = jobFlowItem->getJobType();
JobInfo.m_connectionName = submitItem->connectionName();
JobInfo.m_submitJobId = submitItem->jobID();
JobInfo.m_submitJobStat = submitItem->jobState();
// All valid data stored here
}
file.close();
QDataStream dStreamOut(&file);
dStreamOut >> jobLstCount; /*Count returns zero here insted of 4*/
CascadeJobInfo jobInfo;
// Why jobLstCount is getting zero here
for(int i = 0 ; i < jobLstCount ; i++)
{
dStreamOut >> jobInfo;
}
}
file.open(QFile::ReadWrite);
file.close(); <--- HERE
QDataStream dStream(&file);
You are closing the file as soon as you open it, so basically you are working with an invalid file descriptor which won't work. Put file.close() at the end of the code when you are done.

Cannot open QFile for appending/readwrite

I am trying to use the following code to open the existing file to append data at it's end:
void AddPharmacyForm::addInsertToFile(QString insert)
{
QFile inserts(":/new/prefix1/insertstatements.txt");
if(!inserts.exists())
qDebug() << "File does not exist";
if(inserts.isOpen())
qDebug() << "file is open";
if(inserts.open(QFile::ReadWrite | QFile::Text))
{
// Another workaround- could not open file with append flag
qDebug() << "im here!";
QString currentInserts;
QTextStream out(&inserts);
out >> currentInserts;
out << endl << insert;
inserts.close();
}
else
{
QMessageBox::information(this, tr("Error"), tr("Cannot add new pharmacy! "
"Please contact program designer."
));
qDebug() << "error code: " + QString::number(inserts.error());
return;
}
}
The output of this code is the QMessageBox with the error and in qDebug it produces following line:
"error code: 5"
It does not give notice about file not existing and file being open. I have also tried opening file with different flags: QFile::ReadWrite, QFile::append, QFile::WriteOnly and the same modes within QIODevice. The error code is still the same. When I am opening the file from another class, the file opens without errors (it is not an access error).
What might be causing this problem?
There's no support for writing into the resource system, whether implemented using Qt's resource system or native to the platform. Your application typically has no right to modify its own executable, or the application bundle, or its installation location - it'd be a security risk if it did since bugs in networking code could be easily exploited to infect your user's system. So what you're trying to do is just a bad idea.
Instead, store the modified resources in your application's data folder, and revert to reading from the resource if the file doesn't exist. It is also probably not very wise to append to a file if the file is small: such appends are not atomic and can partially fail, leaving the file corrupted. Using a QSaveFile is guaranteed to either completely succeed or to fail without modifying any data.
An example implementation follows. The src.close() is not necessary to close the file, as QFile will automatically close upon destruction, as it is a proper resource-managing C++ class. By closing it earlier we ensure minimal use of the file descriptor - a finite system resource.
// https://github.com/KubaO/stackoverflown/tree/master/questions/resource-bypass-43044268
#include <QtCore>
const char kInsertsFile[] = ":/insertstatements.txt";
QString toWritableName(const QString & qrcFileName) {
Q_ASSERT (qrcFileName.startsWith(":/"));
QFileInfo info(qrcFileName);
return
QStandardPaths::writableLocation(QStandardPaths::DataLocation)
+ info.path().mid(1) + '/' + info.fileName();
}
QString toReadableName(const QString & qrcFileName) {
Q_ASSERT (qrcFileName.startsWith(":/"));
auto writable = toWritableName(qrcFileName);
return QFileInfo(writable).exists() ? writable : qrcFileName;
}
bool setupWritableFile(QSaveFile & dst, QIODevice::OpenMode mode = {}) {
Q_ASSERT (dst.fileName().startsWith(":/"));
Q_ASSERT (mode == QIODevice::OpenMode{} || mode == QIODevice::Text);
QFile src(toReadableName(dst.fileName()));
dst.setFileName(toWritableName(dst.fileName()));
if (!src.open(QIODevice::ReadOnly | mode))
return false;
auto data = src.readAll();
src.close(); // Don't keep the file descriptor tied up any longer.
QFileInfo dstInfo(dst.fileName());
if (!dstInfo.dir().exists() && !QDir().mkpath(dstInfo.path()))
return false;
if (!dst.open(QIODevice::WriteOnly | mode))
return false;
return dst.write(data) == data.size();
}
bool addInsertToFile(const QString & insert) {
QSaveFile file(kInsertsFile);
if (!setupWritableFile(file, QIODevice::Text))
return false;
if (true) {
// Alternative 1
QTextStream s(&file);
s << insert << '\n';
} else {
// Alternative 2
file.write((insert + '\n').toLocal8Bit());
}
return file.commit();
}
QStringList readInserts() {
QFile file(toReadableName(kInsertsFile));
if (!file.open(QIODevice::ReadOnly))
return {};
return QString::fromLocal8Bit(file.readAll()).split('\n', QString::SkipEmptyParts);
}
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
app.setApplicationName("resource-bypass-42044268");
qDebug() << "Original Inserts:" << readInserts();
auto rc = addInsertToFile("NewInsert");
qDebug() << "Modification status:" << rc;
qDebug() << "Current Inserts:" << readInserts();
}
When you use the Qt Resource System (qrc files) to add files for your project, they are compiled directly into the binary of your application, so are therefore readonly. As the documentation states: -
Resource data can either be compiled into the binary and thus accessed immediately in application code, or a binary resource can be created and at a later point in application code registered with the resource system.
And...
Currently, Qt always stores the data directly in the executable, even on Windows, macOS, and iOS, where the operating system provides native support for resources. This might change in a future Qt release.

Reading from Multiple long .txt files in Qt

I am trying to read data from Multiple files in Qt.
This how I am doing it:
void MainWindow::on_pushButton_3_clicked()
{
QString path = "C:/MyDevelopment/readfiles";
QDir dir(path);
QStringList filters;
filters << "*.txt";
foreach ( QString fileName, dir.entryList(filters, QDir::Files) )
{
QFile readFile(fileName);
if(!readFile.open(QIODevice::ReadOnly | QIODevice::Text ) )
{
qDebug("Failed to read file.....");
//return ;
}
QTextStream in(&fileName);
while (!in.atEnd())
{
QString line = in.readLine();
qDebug() << line;
}
}
it is always going in failed to open. what i am doing wrong here??
in mentioned directory all files are .txt files.

Saving a qlistwidget after closing application

I have a program that allows for a user to create a profile that saves values using qsettings, the user accesses their profile by clicking on the name in a qlistwidget. I am trying to save the names of the profiles by using a text file but I am having trouble saving more than one profile name at a time. thank you! here is the code:
for saving a profilename to the text document
void Profile::writeProfilenames()
{
QString profilename = ui->lineEdit_profilename->text();
profilename = profilename.simplified();
QFile pfile("profilenames.txt");
if (!pfile.open(QFile::WriteOnly | QIODevice::Text))
{
return;
}
QTextStream out(&pfile);
out << profilename;
pfile.flush();
pfile.close();
}
for retrieving the profile names from the document
void Profile::readProfilenames()
{
QFile pfile("profilenames.txt");
if (!pfile.open(QIODevice::ReadOnly |
QIODevice::Text))
{
return;
}
QString proname = pfile.readLine();
QListWidgetItem *itm = new QListWidgetItem;
itm->setText(proname);
ui->listWidget_profiles->insertItem(0,itm);
}
P.S. if you know of a better way to do this then feel free to share! (with example please)
I don't quite see why you're saving the list of names in a text file, while the settings themselves are saved in a platform-specific fashion using QSettings.
The code you show has several problems:
Presumably you don't want to "write" the name to the file, overwriting the existing contents at the beginning, but specifically to append to the file. You also must specify a writable path to the file, so far you're using the current working directory that is: variable, not under your control, and not necessarily writable. Your code also doesn't handle repeated names.
QFile is a proper C++ class, and embodies the RAII principles. You don't have to do anything to flush and close the file. The compiler takes care of generating the proper code for you. That's why you're using C++ and not C, after all. Yes, your code compiles, but it reads like C, and such verbosity is unnecessary and counterproductive.
You're only retrieving one name from the file. You want to retrieve all of them.
I'd say that you should dispense with the file access, set up your application's identification, a crucial prerequisite to using QSettings, and, finally, use them:
struct Profile {
QString name;
int age;
}
void saveProfiles(const QList<Profile> & profiles)
{
QSettings s;
s.beginWriteArray("profiles");
for (int i = 0; i < profiles.size(); ++i) {
s.setArrayIndex(i);
const Profile & p = profiles.at(i);
s.setValue("name", p.name);
s.setValue("age", p.age);
}
s.endArray(); //optional
}
QList<Profile> loadProfiles()
{
QList<Profile> profiles;
QSettings s;
int size = s.beginReadArray("profiles");
for (int i = 0; i < size; ++i) {
s.setArrayIndex(i);
Profile p;
p.name = s.value("name").toString();
p.age = s.value("age").toInt();
profiles << p;
}
s.endArray(); // optional
return profiles;
}
int main(int argc, char ** argv) {
QApplication app(argc, argv);
app.setOrganizationName("fluxD613"); // ideally use setOrganizationDomain instead
app.setApplicationName("fluxer");
...
return app.exec();
}
After a lot more research and trial and error I came up with the following code that does the trick:
this function is implemented when I close the profiles dialog window and return to the main window using QCloseEvent.
void Profile::writeProfilenames()
{
QFile pfile("profilenames.txt");
if (!pfile.open(QFile::WriteOnly | QIODevice::Text))
{
return;
}
for(int row = 0; row < ui->listWidget_profiles->count(); row++)
{
QListWidgetItem *item = ui->listWidget_profiles->item(row);
QTextStream out(&pfile);
out << item->text().simplified() << "\n";
}
pfile.close();
}
reading the list of profilenames is implemented when I open the dialog window just under ui->setup(this).
void Profile::readProfilenames()
{
QFile pfile("profilenames.txt");
if (!pfile.open(QIODevice::ReadOnly |
QIODevice::Text))
{
return;
}
QTextStream in(&pfile);
while (!in.atEnd())
{
QString line = in.readLine();
QListWidgetItem *item = new QListWidgetItem;
item->setText(line);
ui->listWidget_profiles->addItem(item);
}
pfile.close();
}
I am now working on making sure the user does not enter a profilename that already exists and deleting a profilename from the QListWidget.

Resources