[Qt][Linux] List drive or partitions - c++

How I can list drives or mounted partitions using qt?
I tried to use:
foreach( QFileInfo drive, QDir::drives() )
{
qDebug() << "Drive: " << drive.absolutePath();
}
but it shows just root drive.
I also noticed that length of QDir::drives() is 1 but QDir::Drives is 4.

You can use /etc/mtab file to obtain a mountpoints list.
QFile file("/etc/mtab");
if (file.open(QFile::ReadOnly)) {
QStringList mountpoints;
while(true) {
QStringList parts = QString::fromLocal8Bit(file.readLine()).trimmed().split(" ");
if (parts.count() > 1) {
mountpoints << parts[1];
} else {
break;
}
}
qDebug() << mountpoints;
}
Output on my machine:
("/", "/proc", "/sys", "/sys/fs/cgroup", "/sys/fs/fuse/connections", "/sys/kernel/debug", "/sys/kernel/security", "/dev", "/dev/pts", "/run", "/run/lock", "/run/shm", "/run/user", "/media/sf_C_DRIVE", "/media/sf_C_DRIVE", "/media/sf_D_DRIVE", "/run/user/ri/gvfs")
Note that QFile::atEnd() always returns true for this file, so I didn't use it in my code.
QDir::Drives is 4 according to the documentation. It's static integer value of enum item, it doesn't show anything and you shouldn't care about it in most cases. QDir::drives() contains exactly one item (for root filesystems) when executed on Linux.

You need to use platform specific code. And, please, read the docs!
Returns a list of the root directories on this system.
On Windows this returns a list of QFileInfo objects containing "C:/", "D:/", etc. On other operating systems, it returns a list containing just one root directory (i.e. "/").

Qt 5.4+
You can use QStorageInfo class in Qt 5.4+ as follow:
foreach (const QStorageInfo &storage, QStorageInfo::mountedVolumes()) {
if (storage.isValid() && storage.isReady()) {
if (!storage.isReadOnly()) {
// ...
}
}
}
more info

Related

Zip directory recursion

I am working on creating zip archive using old Qt - ZipWriter class. The problem is when I want to add the directory. The default Qt code for addDirectory method - d->addEntry(ZipWriterPrivate::Directory, archDirName, QByteArray());. It does not add any content, only the empty directory. So, I have improved it to add the directories and content as well.
My code:
QList<QString> dirs;
int recursion = 0;
void ZipWriter::addDirectory(const QString &dirPath)
{
QDir archDir(dirPath);
archDir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
dirs << addDirSeparator(archDir.dirName());
if (archDir.exists()) {
QString archDirName = "";
if (recursion > 0) {
for (int i = recursion; i < dirs.count(); i++) {
archDirName = dirs.first().append(dirs.at(i));
}
} else {
archDirName = dirs.at(recursion);
}
if (!archDir.isEmpty()) {
const QStringList archFileList = archDir.entryList();
if (archFileList.count() > 0) {
for (QString archFile : archFileList) {
QFileInfo archFileInfo(QDir::toNativeSeparators(QString("%1/%2").arg(archDir.absolutePath(), archFile)));
if (archFileInfo.isDir()) {
recursion++;
addDirectory(archFileInfo.absoluteFilePath());
} else {
QFile zipFile(archFileInfo.absoluteFilePath());
zipFile.open(QIODevice::ReadOnly);
addFile(QString("%1%2").arg(archDirName, archFile), zipFile.readAll());
zipFile.close();
}
}
}
} else {
d->addEntry(ZipWriterPrivate::Directory, archDirName, QByteArray());
}
}
}
Now, it adds the directory and content recursively but it has issue when directory is on the same level, it appends it to the end. I think, I must use the STL container to keep track of the directory for example QMap but the question is how to get the current directory level? Any ideas? Thank you.
Updated: 01.05.2022
I have change my code to this:
void ZipWriter::addDirectory(const QString &dirPath)
{
QDirIterator dirIt(dirPath, QDir::AllEntries | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
while (dirIt.hasNext()) {
QString archDirPath = dirIt.next();
QFile zipFile(archDirPath);
zipFile.open(QIODevice::ReadOnly);
if (!dirIt.fileInfo().isDir()) {
addFile(archDirPath, zipFile.readAll());
}
zipFile.close();
}
}
It adds everything recursively and in correct order but I have another issue. Now, it adds the full path to the archive. For example, I want to add this folder and it's content to the archive: 22610.1_amd64_en-us_professional_00fb7ba0_convert.
In the archive I get: C:\Users\userProfile\Downloads\22610.1_amd64_en-us_professional_00fb7ba0_convert. Any ideas how to make this relative path or trim it? Thank you.
You can use QDirIterator to recursively iterate over directory and subdirectories, and I believe you dont need to add nonempty directories at all, just files will be fine.
And why would you use stl container in qt, please use qt containers.

Issues trying to make a filter using Qt

I'm trying to make my software filter a list of elements.
I think I need to put my data in a TableWidget because I have to display other information.
I also put 3 Line Edit to search respectively in each category (called leName, leSource, leDestination)
so I tried to implement my filter for the name property, for now I have :
void MyClass::on_leName_textEdited(const QString &arg1)
{
for (int i=0;ui->tableWidget->rowCount()-1;i++)
{
qDebug()<<"before if";
if(ui->tableWidget->item(0,1)->text().contains(arg1) //tried with &arg1, I have the same issue, for now
{
qDebug()<<"If validated";
ui->tableWidget->showRow(i);
}else{
qDebug()<<"If not validated"
ui->tableWidget->hideRow(i)
}
}
}
When I hit a key, my soft crashes
I get "Before if", "If (not) validated", "Before if" from qDebug
I launched with debbugger and got Segmentation fault as error
not sure what I could add as detail about my error
Maybe I did nothing in the good way, I'm no expert in Qt nor c++
If you have any idea of what I should do to correct this, I would appreciate it =)
The fact that a cell exists does not imply that it has an associated QTableWidgetItem, so you must verify that it is not null.
QTableWidgetItem * item = ui->tableWidget->item(0, 1);
if(item && item->text().contains(arg1))
{
qDebug() << "If validated";
ui->tableWidget->showRow(i);
}else{
qDebug() << "If not validated"
ui->tableWidget->hideRow(i)
}

C++ Transfer Files From Qt to External USB Drive

I am new in Qt and I need help in transferring all files from a specific path of the local machine to an external USB Drive.
Copying a single file
You can use QFile::copy.
QFile::copy(srcPath, dstPath);
Note: this function doesn't overwrite files, so you must delete previous files if they exist:
if (QFile::exist(dstPath)) QFile::remove(dstPath);
If you need to show an user interface to get the source and destination paths, you can use QFileDialog's methods to do that. Example:
bool copyFiles() {
const QString srcPath = QFileDialog::getOpenFileName(this, "Source file", "",
"All files (*.*)");
if (srcPath.isNull()) return false; // QFileDialog dialogs return null if user canceled
const QString dstPath = QFileDialog::getSaveFileName(this, "Destination file", "",
"All files (*.*)"); // it asks the user for overwriting existing files
if (dstPath.isNull()) return false;
if (QFile::exist(dstPath))
if (!QFile::remove(dstPath)) return false; // couldn't delete file
// probably write-protected or insufficient privileges
return QFile::copy(srcPath, dstPath);
}
Copying the whole content of a directory
I'm extending the answer to the case srcPath is a directory. It must be done manually and recursively. Here is the code to do it, without error checking for simplicity. You must be in charge of choosing the right method (take a look at QFileInfo::isFile for some ideas.
void recursiveCopy(const QString& srcPath, const QString& dstPath) {
QDir().mkpath(dstPath); // be sure path exists
const QDir srcDir(srcPath);
Q_FOREACH (const auto& dirName, srcDir.entryList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name)) {
recursiveCopy(srcPath + "/" + dirName, dstPath + "/" + dirName);
}
Q_FOREACH (const auto& fileName, srcDir.entryList(QStringList(), QDir::Files, QDir::Name)) {
QFile::copy(srcPath + "/" + fileName, dstPath + "/" + fileName);
}
}
If you need to ask for the directory, you can use QFileDialog::getExistingDirectory.
Final remarks
Both methods assume srcPath exists. If you used the QFileDialog methods it is highly probable that it exists (highly probable because it is not an atomic operation and the directory or file may be deleted or renamed between the dialog and the copy operation, but this is a different issue).
I have solved the problem with the QStorageInfo::mountedVolumes() which return the list of the devices that are connected to the Machine. But all of them won't have a name except the Pendrive or HDD. So (!(storage.name()).isEmpty())) it will return the path to only those devices.
QString location;
QString path1= "/Report/1.txt";
QString locationoffolder="/Report";
foreach (const QStorageInfo &storage, QStorageInfo::mountedVolumes()) {
if (storage.isValid() && storage.isReady() && (!(storage.name()).isEmpty())) {
if (!storage.isReadOnly()) {
qDebug() << "path:" << storage.rootPath();
//WILL CREATE A FILE IN A BUILD FOLDER
location = storage.rootPath();
QString srcPath = "writable.txt";
//PATH OF THE FOLDER IN PENDRIVE
QString destPath = location+path1;
QString folderdir = location+locationoffolder;
//IF FOLDER IS NOT IN PENDRIVE THEN IT WILL CREATE A FOLDER NAME REPORT
QDir dir(folderdir);
if(!dir.exists()){
dir.mkpath(".");
}
qDebug() << "Usbpath:" <<destPath;
if (QFile::exists(destPath)) QFile::remove(destPath);
QFile::copy(srcPath,destPath);
qDebug("copied");
}
}
}
I had to create a folder as well as in USB because of my requirements and I have given a static name for the files. Then I just copied the data from file of the local machine to the file which I have created in USB with the help of QFile::copy(srcPath, dstPath). I hope it will help someone.

using QFileSystemWatcher::Files() to get file count of watched folder example? count is always 0?

I have tried to figure this out over the weekend, but to no avail. I cant seem to find an example using QFileSystemWatcher::Files() directly so i thought i would ask.
I have a program that :
lets the user select a 'source' folder.
press a button to start watching that source folder for new files
there is a signal emitted using 'directoryChanged()' where i try to update the count every time a file is added or removed.
I will profess that my implementation of QfileSystemWatcher is probably not correct. but this code is working and does trigger the signal/slot. but the count is always zero...
from mainwindow.cpp...
the signal:
//connect push buttons
QObject::connect(ui->startButton, SIGNAL(clicked()),
this, SLOT(startButtonClicked()));
//link qfilesystemwatcher with signals and slots
QObject::connect(&hotfolder, SIGNAL(directoryChanged(QString)), this, SLOT(hotfolderChanged()));
the slots:
void MainWindow::startButtonClicked(){
//start the file system watcher using the 'source folder button'
//first, get the resulting text from the source folder button
QString sourceText = ui->sourceBtnLineEdit->text();
ui->statusbar->showMessage(sourceText);
//convert the text from source button to a standard string.
string filePath = sourceText.toStdString();
cout << filePath << endl;
//call method to add source path to qfilesystemwatcher
startWatching(sourceText);
}
void MainWindow::hotfolderChanged(){
int fileCount = filesWatched();
ui->statusbar->showMessage(QString::number(fileCount));
}
from magickWatcher.h
#ifndef MAGICKWATCHER_H
#define MAGICKWATCHER_H
#include <QFileSystemWatcher>
#include <mainwindow.h>
//create the qFileSystemWatcher
QFileSystemWatcher hotfolder;
//add folder to qfilesystemwatcher
//starts watching of folder path
int startWatching( QString folder){
hotfolder.addPath(folder);
cout << "hotfolder created!" << endl;
return 0;
}
//get file list of folder being watched
int filesWatched(){
QStringList watchedList = hotfolder.files();
//report out each line of file list
for (int i = 0; i < watchedList.size(); ++i){
cout << watchedList.at(i).toStdString() << endl;
cout << "is this looping?!!" << endl;
}
return watchedList.count();
}
#endif // MAGICKWATCHER_H
How can i use QFileSystemWatcher to get the file count of the watched folder? I know about QDir and its options but want to specifically know how to use QFileSystemWatcher.
I am still wrapping my head around c++ in general so thank you for any advice or tips as well. I think maybe my problem is how i am implementing QFileSystemWatcher.
Some relevant links i have used:
QFileSystemWatcher working only in main()
http://doc.qt.io/qt-5/qfilesystemwatcher.html#files
First let's have a closer look at docs (bold format is mine):
QFileSystemWatcher examines each path added to it. Files that have been added to the QFileSystemWatcher can be accessed using the files() function, and directories using the directories() function.
So, files() only returns a list of files which you have already added to the watcher using addPath() method, NOT a list of files implicitly being watched by adding a directory.
You can get information about files in the watched directory e.g. by using QDir::entryInfoList with filters applicable in your case. At least QDir::Files and possibly QDir::NoDotAndDotDot would make sense.
//get file list of folder being watched
int filesWatched() {
QString folder = "/path/to/hotfolder/";
QDir monitoredFolder(folder);
QFileInfoList watchedList =
monitoredFolder.entryInfoList(QDir::NoDotAndDotDot | QDir::Files);
QListIterator<QFileInfo> iterator(watchedList);
while (iterator.hasNext())
{
QFileInfo file_info = iterator.next();
qDebug() << "File path:" << file_info.absoluteFilePath();
}
return watchedList.count();
}

How to filter if a directory is root directory in windows/qt?

I am showing contents of folder (only show certain files) when user is typing path. I don't want to show content if its a root folder (c:\ drive) because it searches all sub directories and it would take too long and is not needed.
The problem is if I type "c:\\" in the edit box, it still searches the C:\ drive but QDir::isRoot() doesn't pick it up. How can I catch path accurately that could be root path or even program files path? I am using Windows 7.
void MainWindow::on_lineEditSourceFolder_textChanged(const QString &arg1)
{
//qDebug() << "edit text changed: " << arg1;
QDir dir( arg1 ) ;
if ( !dir.exists() )
{
model->clear();
return;
}
QString dirPath = dir.absolutePath();
if (dir.isRoot() )
{
qDebug() << arg1 << " is root";
return;
}
searchFiles( dirPath );
}
Looks like a bug in QT. Have a look at the source of QDir.isRoot() to be sure, then submit a bug report.
But the QT docs might show a workaround. Try changing this:
QString dirPath = dir.absolutePath();
into
QString dirPath = dir.canonicalPath();
Here's isRoot() behavior:
returns false on c
returns false on c:
returns true on c:\
So when you enter c:, isRoot() returns false and searchFiles() will be called. When you subsequently press \, isRoot() returns true, but you did not call model->clear() before returning. This gives the impression that c:\ still call searchFiles().
So you should do a clear before returning:
if (dir.isRoot() )
{
qDebug() << arg1 << " is root";
model->clear();
return;
}
If you don't want c: to search files too, append a \ to the directory before checking for root:
void MainWindow::on_lineEditSourceFolder_textChanged(const QString &arg1)
{
QString temp = arg1 + '\\';
QDir dir( temp ) ;
....