how do i change a file extension on qt - c++

I have a piece of code to download a file from server. However, due to server constraint, I can not put .exe file at server. So I rename my XXX.exe file to XXX.alt(just a random extension) and put it on server.
Now my code can download XXX.alt, but how can I change the file name from XXX.alt back to XXX.exe when in QT environment?

Use QFileInfo to get the path without the last extension then append the new extension.
QFileInfo info(fileName);
QString strNewName = info.path() + "/" + info.completeBaseName() + ".exe";

Just use rename function from 'stdio.h'.
char oldname[] ="XXX.alt";
char newname[] ="XXX.exe";
result= rename( oldname , newname );
if ( result == 0 )
puts ( "File successfully renamed" );
else
perror( "Error renaming file" );

One solution is to find the last '.', and replace the substring from that position to the end with the substring you want.
Exactly how to do it, there are many ways using both std::string and QString, as both support finding characters in the string (and doing a search from the end to the beginning as well), and replace substrings.

Prefer to use baseName()
QFileInfo info(fileName);
QString strNewName = info.path() + info.baseName() + ".exe";
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)

Related

QProcess::execute Environment Variables Expanded Strings

How do I get this to work:
QProcess::execute("%windir%\system32\SnippingTool.exe")
I assume expanded environment variables strings are being ignored by QProcess.
I guess I'll need to parse the string and see if % exists and then get the environment variable to complete the full string path. Sounds like hassle and something that should be handled by QProcess. Am I missing something?
Thanks in advance! :)
If you want to use %windir% directly, you can do something like this:
QProcess::execute("cmd.exe /c start /WAIT "" %windir%\\system32\\SnippingTool.exe");
Else, you can use for example qgetenv("windir") or qEnvironmentVariable("windir") to get the windows folder path.
Hope it helps you.
Thanks to #TomKim answer for handling expanded strings in his answer, I got that problem solved. But unfortunately white spaces caused other issues for me that made me come up with this solution that hopefully will help others. Not the prettiest solution though, but it does exactly I needed for multiple platforms:
void QuickCut::executeProcess(const std::string & szProc, const std::string & szArgs)
{
// QProc won't expand environment variable strings.
// Invoking using the user console will allow for expanded string to work as expected.
#ifdef Q_OS_WIN
QString szCommand = "cmd /c start \"\" \"" + QString::fromStdString(szProc) + "\"";
QString szExt = ".cmd";
#elif Q_OS_UNIX
QString szCommand = "sh -c '" + QString::fromStdString(szProc) + "'";
QString szExt = ".sh";
#endif
QStringList qArgsTmp = QString::fromStdString(szArgs).trimmed().split(",");
for (auto && arg : qArgsTmp)
{
QString argTrimmed = arg.trimmed();
if (argTrimmed.isEmpty()) continue;
szCommand += " " + argTrimmed;
}
qDebug() << "[QuickCut::executeProcess] - Execute Command: " << szCommand;
QString szFilePath = applicationDirPath() + "/tempCmd" + szExt;
QFile file(szFilePath);
file.open(QIODevice::ReadWrite);
QTextStream ts(&file);
ts << szCommand;
file.close();
QProcess::execute(szFilePath);
file.remove();
}

How to manage file (replace, delete...) in Qt?

I've a text file with its backup copy: backup copy has the same name with only a "2" as last character of the extension (example: Original: Myfile.txt - Backup: Myfile.txt2).
Sometimes I need to replace the original one with the backup; I do the following:
QFile BackupFile("Myfile.txt2"); // backup copy
QString nameFile = BackupFile.fileName();// name of backup copy of file
nameFile.chop(1); // remove the last letter of file name, so nameFile now is the same of Original file
QFile originalFile(nameFile); // Original copy
originalFile.remove(); // delete the original file
BackupFile.rename(nameFile); // rename the backup file as original
BackupFile.close(); // close the file
This works, but it seems too complex. I'd like something easier.
Do you have any suggestion?
I think this code can be simple method. However, you should add code for error case, such as 'check whether backup file exist.', etc..
auto ReplaceWithBackup = []( QString& backupName ) -> bool
{
QString originName = backupName;
originName.chop( 1 );
if ( QFile::exists( originName ) )
{
QFile::remove( originName );
}
return QFile::rename( backupName, originName );
};
if ( ReplaceWithBackup( "Myfile.txt2") == false )
{
// error
}
If the files are in the same directory, you can use QDir::rename. Otherwise reading one file and writing in the other is required. Here is my version of the first case.
// Generate some test data
{
QFile bf( "Myfile.txt2" );
bf.open(QIODevice::WriteOnly);
bf.write("Backup data");
QFile( "Myfile.txt" ).open(QIODevice::WriteOnly);
}
//Assume you know which back-up file to restore
QString backupFn("Myfile.txt2");
//Actual code
QString origFn = backupFn.mid( 0, backupFn.size()-1 ); //"guess" the original file name.
QFile::remove( origFn ); //Use static version to delete file by name (No QFile instance required)
QDir().rename(backupFn,origFn);
However, each line requires many checks and validations e.g. is the provided backup-file name a valid backup name, did remove/rename succeded, etc, etc.

Add unique suffix to file name

Sometimes I need to ensure I'm not overwriting an existing file when saving some data, and I'd like to use a function that appends a suffix similar to how a browser does it - if dir/file.txt exists, it becomes dir/file (1).txt.
This is an implementation I've made, that uses Qt functions:
// Adds a unique suffix to a file name so no existing file has the same file
// name. Can be used to avoid overwriting existing files. Works for both
// files/directories, and both relative/absolute paths. The suffix is in the
// form - "path/to/file.tar.gz", "path/to/file (1).tar.gz",
// "path/to/file (2).tar.gz", etc.
QString addUniqueSuffix(const QString &fileName)
{
// If the file doesn't exist return the same name.
if (!QFile::exists(fileName)) {
return fileName;
}
QFileInfo fileInfo(fileName);
QString ret;
// Split the file into 2 parts - dot+extension, and everything else. For
// example, "path/file.tar.gz" becomes "path/file"+".tar.gz", while
// "path/file" (note lack of extension) becomes "path/file"+"".
QString secondPart = fileInfo.completeSuffix();
QString firstPart;
if (!secondPart.isEmpty()) {
secondPart = "." + secondPart;
firstPart = fileName.left(fileName.size() - secondPart.size());
} else {
firstPart = fileName;
}
// Try with an ever-increasing number suffix, until we've reached a file
// that does not yet exist.
for (int ii = 1; ; ii++) {
// Construct the new file name by adding the unique number between the
// first and second part.
ret = QString("%1 (%2)%3").arg(firstPart).arg(ii).arg(secondPart);
// If no file exists with the new name, return it.
if (!QFile::exists(ret)) {
return ret;
}
}
}
QTemporaryFile can do it for non-temporary files, despite its name:
QTemporaryFile file("./foobarXXXXXX.txt");
file.open();
// now the file should have been renamed to something like ./foobarQSlkDJ.txt
file.setAutoRemove(false);
// now the file will not be removed when QTemporaryFile is deleted
A better solution is to use GUID
Or you can generate a hash based on bytes collected from within a file, either randomly or based on some data property that is fairly unique from file to file.

Regular Expression for validating Windows-based file paths including UNC paths

I wanted to validate a file name along with its full path. I tried certain Regular Expressions as below but none of them worked correctly.
^(?:[\w]\:|\\)(\\[a-z_\-\s0-9\.]+)+\.(txt|gif|pdf|doc|docx|xls|xlsx)$
and
^(([a-zA-Z]\:)|(\\))(\\{1}|((\\{1})[^\\]([^/:*?<>""|]*))+)$
etc...
My requirement is as mentioned below:
Lets say if the file name is "c:\Demo.txt" then it should check every possibilites like no double slash should be included(c:\\Demo\\demo.text) no extra colon like(c::\Demo\demo.text). Should accept UNC files like(\\staging\servers) and others validation as well. Please help. I am really stuck here.
Why are you not using the File class ?
Always use it !
File f = null;
string sPathToTest = "C:\Test.txt";
try{
f = new File(sPathToTest );
}catch(Exception e){
Console.WriteLine(string.Format("The file \"{0}\" is not a valid path, Error : {1}.", sPathToTest , e.Message);
}
MSDN : http://msdn.microsoft.com/en-gb/library/system.io.file%28v=vs.80%29.aspx
Maybe you're just looking for File.Exists ( http://msdn.microsoft.com/en-gb/library/system.io.file.exists%28v=vs.80%29.aspx )
Also take a look to the Path class ( http://msdn.microsoft.com/en-us/library/system.io.path.aspx )
The GetAbsolutePath could be one way to get what you want! ( http://msdn.microsoft.com/en-us/library/system.io.path.getfullpath.aspx )
string sPathToTest = "C:\Test.txt";
string sAbsolutePath = "";
try{
sAbsolutePath = Path.GetAbsolutePath(sPathToTest);
if(!string.IsNullOrEmpty(sAbsolutePath)){
Console.WriteLine("Path valid");
}else{
Console.WriteLine("Bad path");
}
}catch(Exception e){
Console.WriteLine(string.Format("The file \"{0}\" is not a valid path, Error : {1}.", sPathToTest , e.Message);
}
If you are interested only in the filename part (and not the whole path because you get the file via upload) then you could try something like this:
string uploadedName = #"XX:\dem<<-***\demo.txt";
int pos = uploadedName.LastIndexOf("\\");
if(pos > -1)
uploadedName = uploadedName.Substring(pos+1);
var c = Path.GetInvalidFileNameChars();
if(uploadedName.IndexOfAny(c) != -1)
Console.WriteLine("Invalid name");
else
Console.WriteLine("Acceptable name");
This will avoid the use of Exceptions as method to drive the logic of your code.

C++ iterating through files and directories

I'm working on a C++ program that will automatically backup my work to my FTP server. So far I am able to upload a single file, by specifying a file name using this
CString strFilePath = szFile ;
int iPos = strFilePath.ReverseFind('\\');
CString strFileName = strFilePath.Right((strFilePath.GetLength()- iPos-1) );
CString strDirPath = m_szFolderDroppedIn ;
strDirPath = strDirPath.Mid(0,strDirPath.GetLength() - 1);
int iPost = strDirPath.ReverseFind('\\');
CString strDirName = strDirPath.Right((strDirPath.GetLength()- iPost -1) );
bool curdir = ftpclient.SetServerDirectory((char*)strDirName.GetBuffer(strDirName.GetLength()));
//Upload to Server
int uploadret = ftpclient.PutFile(szFile,(char*)strFileName.GetBuffer(strFileName.GetLength()),0,true,dwLastError);
m_lsDroppedFiles.RemoveAll();
break;
}
Now I want to be able to iterate through a directory (Which contains subdirectories) and recursively call. I'm having a problem getting a hold of the files in the directory.
Any help or code snippet...
Since you are using MFC, you can use the CFileFind class. Example code is given in MSDN. Alternatively, you can use boost.filesystem for the same.
#Swapnil: If you use boost::filesystem, there is a recursive_directory_iterator