Removing extension of a file name in Qt - c++

I'm using Qt to get a file name from the user:
QString fileName = QFileDialog::getOpenFileName(this,tr("Select an image file"),"d:\\",tr("Image files(*.tiff *.tif )"));
It works, but I need the file name without its extension, is it possible in Qt??
whenn I try :
QString f = QFileInfo(fileName).fileName();
f is like "filename.tif", but I want it to be "filename".

QFileInfo has two functions for this:
QString QFileInfo::completeBaseName () const
Returns file name with shortest extension removed (file.tar.gz -> file.tar)
QString QFileInfo::baseName () const
Returns file name with longest extension removed (file.tar.gz -> file)

To cope with filenames containing multiple dots, look for the last one and take the substring until that one.
int lastPoint = fileName.lastIndexOf(".");
QString fileNameNoExt = fileName.left(lastPoint);
Of course this can (and should) be written as a helper function for reuse:
inline QString withoutExtension(const QString & fileName) {
return fileName.left(fileName.lastIndexOf("."));
}

You can split fileName with "." as separator like this:
QString croped_fileName=fileName.split(".",QString::SkipEmptyParts).at(0);
or use section function of QString to take the first part before "." like this:
QString croped_fileName=fileName.section(".",0,0);

You can use QString::split and use the . as the place where to split it.
QStringList list1 = str.split(".");
That will return a QStringList with {"filename", "extenstion"}. Now you can get your filename without the extension.

To get absolute path without extension for QFileInfo fileInfo("/a/path/to/foo.tar.gz") you can use:
QDir(file_info.absolutePath()).filePath(file_info.baseName());
to get "/a/path/to/foo" or
QDir(file_info.absolutePath()).filePath(file_info.completeBaseName());
to get "/a/path/to/foo.tar"

Related

Execute Command with QProcess and Store result in QStringList

I have written the following function which executes a windows enumeration command for getting shared folders and store the result in a QString.
QProcess p;
p.setProgram("wmic");
p.setArguments({"share", "get", "name"});
p.start();
if (!p.waitForFinished()) {
return;
}
const QString output = p.readAllStandardOutput();
qDebug () << output;
const QString error = p.readAllStandardError();
if (!error.isEmpty()) {
qDebug () << error;
}
But the output has a lot of delimiters like "\n\r" ... so I wanted to strip all of those delimiters from my string output. In the next step, you consider we will have a result like the following one:
C$
D$
E$
IPC$
So I wanted to save these names in a QStringList, or something like a list which I can append those names in combo widget independently. How can I do that?
You could just use qstring split:
QStringList list = output.split("\n", QString::SkipEmptyParts);
If you need a more "intelligent" split that you can pass in a regex:
list = output.split(QRegExp("...some regex..."));
The skip empty parts just "removes"/ignores any values that would be empty - I don't think you need that in this case

QDirIterator - Skip Folders and its subfolders

How can you skip folders with the QDirIterator?
I've tried it with:
QString nameFilter = "*.h";
QDirIterator dirIterator(folder, nameFilter, QDir::Files, QDirIterator::Subdirectories);
QString str("folder");
QStringList filenames;
while (dirIterator.hasNext())
{
if(dirIterator.next() == str) continue;
filenames.append(dirIterator.next());
}
but it only ignores the specific folder but not its subdirectories.
Any idea?
Bellow instruction working 100 percent :
This method QString QDirIterator::next() Advances the iterator to the next entry, and returns the "file path" of this new entry. If hasNext() returns false, this function does nothing, and returns a null QString.
If QDirIterator found a file with specific filter (based on const QStringList &nameFilters parameter) then QDirIterator::next() returns "file-path" and you cannot compare the whole "file-path" with "skiped-folder" to iterate!
Because of this i had to write a function as a directory parser as bellow :
QStringList Widget::getCurrDirsOfFile(const QFileInfo &file_info, const QString &default_folder)
{
QString file_path = file_info.filePath();
QString file_name = file_info.fileName();
file_path.truncate(file_path.lastIndexOf("/" + file_name));
file_path = file_path.mid(file_path.lastIndexOf("/") + 1);
return file_path;
}
This function get "file-path" and return last "folder-name's" of it like bellow :
input : /home/msi/Desktop/123/untitled/123/widget.h
output(list) : 123, 123
We have QString skiped_dir("untitled"); as skiped folders!
In this state when you got something excluding 123 "folder-name's", you can append that file to QStringList filenames :
if(folder_list.indexOf(QRegExp(skiped_dir)) == -1)
filenames.append(it.filePath());
So try this (notice in comments) :
void Widget::btn_iterate_clicked()
{
// folder to iterate
QString folder("/home/msi/Desktop/");
// folder-name you want to skip
QString skiped_dir("untitled");
// file-names which are match with .h filter stored in filenames list
QStringList filenames;
// this list used in QStringList getCurrDirsOfFile() method
QStringList folder_list;
// iterator
QDirIterator it(folder, QStringList() << "*.h" , QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) // if next object exist for iterate
{
// we have the file with .h extension
it.next();
// get previous folders that exist in filepath address of it.fileInfo()
folder_list = getCurrDirsOfFile(it.fileInfo(), folder);
// if folder_list contained skiped folder then reject that or appent it
if(folder_list.indexOf(QRegExp(skiped_dir)) == -1)
filenames.append(it.filePath());
}
for(int i = 0;i < filenames.count();i++)
{
QMessageBox::information(this, "", filenames.at(i));
}
}
Suppose we have bellow tree (directories) :
This program just shows :
/home/msi/Desktop/build-untitled-Desktop_Qt_5_0_2_GCC_64bit-Debug/ui_widget.h
/home/msi/Desktop/1/1.h
I know this is a bit old, but your original code was close...there's two problems. First, the iterator covers every entry and what it returns is a full path and filename, not just the entry name within the current directory. Checking for an exact match is the problem rather than for containment. The second issue is that you have two calls to "next" without a call to "hasNext" between them, so it's possible you'll have a crash.
while (dirIterator.hasNext())
{
QString fname = dirIterator.next ();
if (fname.contains (str)) continue;
filenames.append (fname);
}
Note that you may need to be more specific with the value of "str". Any filename could contain the word "folder", so you'll probably want to check for str.endsWith ("/folder") as well as str.contains ("/folder/").
If you inspect the values returned from "next", you'll better see how to compare what you're excluding to the current entry, so just tweak the string comparison to get what you want.

How do I get the value of text inside of the file using Qt?

The data of my file.txt is as below:
Student_ID=0001
Student_Name=joseph
Student_GradeLevel=2
How do I get the value, let say I want to get the Student_ID using Qt.
Thanks.
Take a look at this function, it can be used to find any value you want in your input file, where all lines are in the format you've posted above (key=value). If the key is not found, it returns an empty QString() object.
QString findValueInFile(QString key, QString filename) {
QFile file(filename);
if(file.open(QIODevice::ReadOnly)) {
QTextStream txtStr(&file);
QStringList fileContent = txtStr.readAll().split('\n');
for(auto &&line : fileContent) {
if(line.contains(key)) return line.split(QChar('='))[1];
}
file.close();
}
return QString(); // not found
}
Now you call it somewhere, e.g.:
qDebug() << findValueInFile("Student_ID", "file.txt");
qDebug() << findValueInFile("Student_Name", "file.txt");
This function can be easily modified if you replace your = sign with other delimiter e.g. => or sth else. However for key=value format there is a special QSettings class (mentioned by sebastian) that can allow you to read those values even easier:
QSettings file("file.txt", QSettings::IniFormat);
qDebug() << file.value("Student_Name").toString(); // et voila!
You can probably also use QSettings, as they are able to read ini files.
There are some caveats though regarding backslashes which might be important to you (though they aren't for the example you posted): http://doc.qt.io/qt-4.8/qsettings.html#Format-enum
QSettings iniFile("myfile.txt", QSettings::IniFormat);
// now get the values by their key
auto studentId = iniFile.value("Student_ID").toString().toInt();
I'm more of a PyQt user, so: apologies if I got some C++ specifics wrong...

Qt - copy a file from one directory to another

I am using QT, I am not able to find out how to copy a file from one directory to another? How can I achieve this?
You can use QFile which provides a copy method.
QFile::copy("/path/file", "/path/copy-of-file");
If destination file exist, QFile::copy will not work. The solution is to verify if destination file exist, then delete it:
if (QFile::exists("/path/copy-of-file"))
{
QFile::remove("/path/copy-of-file");
}
QFile::copy("/path/file", "/path/copy-of-file");
The following code works in windows for specified reasons. This will set the path to specified drive and create the folder you created in Under UI Mode. Then copies the file from source to destination. Here the source is installation directory contained some files which are used for plotting curves. this file are not modified by users. They just use it.
hence this works as copy from installation directory to specified folder
void MainWindow::on_pushButton_2_clicked()
{
QString str5 = ui->lineEdit->text();
QString src = "."; QString setpath;
QDir dir(src);
if(!dir.exists()){
return;
}
dir.cdUp();
//dir.cdUp();
setpath = "E://";
dir.setPath(setpath);
QString dst_path = str5 + QDir::separator() ;
dir.mkpath(dst_path);
dir.cd(dst_path);
QString filename = "gnu.plt";
QString filename2 = "Load curve.plt";
QString filename3 = "tube temp.plt";
QFile file(filename);
QFile file1(filename2);
QFile file2(filename3);
file.copy(src+QDir::separator()+filename, setpath+QDir::separator()+str5+QDir::separator()+filename);
file1.copy(src+QDir::separator()+filename2, setpath+QDir::separator()+str5+QDir::separator()+filename2);
file2.copy(src+QDir::separator()+filename3, setpath+QDir::separator()+str5+QDir::separator()+filename3);
}

How do I get the correct case of a path?

I have a small but itching problem. How do I get the correct case for a Windows path in Qt?
Let's say i have a path c:\documents and settings\wolfgang\documents stored in a QString str and i want to know the correct case, here C:\Document and Settings\Wolfgang\Documents. QDir(str).absolutePath() doesn't get me the path with correct case.
Any suggestions, since I have no clue what else i could try?
Thank you for your time!
There isn't a simple way to do this, but you can try doing a QDir.entryList, and then do a case insensitive search on the results. This will provide you with the correct filename. You'll then need to get the absolutePath for that result.
This should give you the preserved-case for the path/filename.
I think the solution currently accepted by the OP, with listing all children items on each directory level of the path, is really inefficient, quick and dirty. There must be a better way. Because this problem with case-correct path relates only to Windows (other platforms are case-sensitive, AFAIK), I think it is perfectly correct to use #ifdef and call to Windows API and write something like this:
#if defined(Q_OS_WIN32)
#include <Windows.h>
// Returns case-correct absolute path. The path must exist.
// If it does not exist, returns empty string.
QString getCaseCorrectPath(QString path)
{
if (path.isEmpty())
return QString();
// clean-up the path
path = QFileInfo(path).canonicalFilePath();
// get individual parts of the path
QStringList parts = path.split('/');
if (parts.isEmpty())
return QString();
// we start with the drive path
QString correctPath = parts.takeFirst().toUpper() + '\\';
// now we incrementally add parts one by one
for (const QString &part : qAsConst(parts))
{
QString tempPath = correctPath + '\\' + part;
WIN32_FIND_DATA data = {};
HANDLE sh = FindFirstFile(LPCWSTR(tempPath.utf16()), &data);
if (sh == INVALID_HANDLE_VALUE)
return QString();
FindClose(sh);
// add the correct name
correctPath += QString::fromWCharArray(data.cFileName);
}
return correctPath;
}
#endif
I have not tested it, there might be some minor issues. Please let me know if it does not work.
You can use QFileInfo for that and the function
QString QFileInfo::absoluteFilePath () const will return the absolute file path.
E.g:
QFileInfo yourFileInfo(yourPath);
QString correctedCasePath = yourFileInfo.absoluteFilePath ();
Another advantage is that, yourPath can be a QFile or QString so that you can use it directly with the handle currently you are having. Besides these, there are other operations are also available through QFileInfo that can obtain useful information about the file being referred to..
Hope it helps..