C++ Transfer Files From Qt to External USB Drive - c++

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.

Related

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

Select file/directory path using QFileDialog in Qt

I want to show a dialog to user to select a file/directory in qt.
I tried using QFileDialog methods to get it, but either i can set file mode or directory mode, could not able to set both. if I set QFileDialog::Directory as file mode it shows directories as well as files, but could not able to select any file.
Here is the example code I tried...
QFileDialog dialog;
dialog.setFileMode(QFileDialog::Directory);
dialog.setOption(QFileDialog::DontUseNativeDialog,true);
dialog.setOption(QFileDialog::DontResolveSymlinks);
dialog.setNameFilterDetailsVisible(true);
dialog.setViewMode(QFileDialog::Detail);
QStringList filters;
filters <<"Any files (*)"
<<"Text files (*.txt)"
<<"Image files (*.png *.xpm *.jpg)";
dialog.setOption(QFileDialog::HideNameFilterDetails,false);
dialog.setNameFilters(filters);
int res = dialog.exec();
QDir directory;
QString file = directory.currentPath();
if (res)
{
directory = dialog.selectedFiles()[0];
QStringList filesList = directory.entryList(QDir::Files);
QString fileName;
foreach(fileName, filesList)
{
qDebug() << "FileName " << fileName;
}
}
Is there is any way get the path of selected file or directory ?

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

Can't create a .db file in assets folder

I am trying to create a quizz.db file in assets folder by first creating a temporary quizz.db in data folder and then creating tables inside it and then copy it to the assets folder. By debugging the code it shows that the folder is created. But I can't find it in assets folder. Here is the code,
#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>
#include <bb/data/SqlDataAccess>
using namespace bb::cascades;
using namespace bb::data;
SQLTest::SQLTest(bb::cascades::Application *app): QObject(app)
{
const QString fileName = QString("quizz.db");
QString dataFolder = QDir::homePath();
QString newFileName = dataFolder + "/" + fileName;
QTemporaryFile file(newFileName);
// Open the file that was created
if (file.open())
{
// Create an SqlDataAccess object
SqlDataAccess sda(newFileName);
// Create a table called Employee in the database file
sda.execute("CREATE TABLE Employee( firstName VARCHAR(50),lastName VARCHAR(50), salary INT);");
// Insert employee records into the table
sda.execute("INSERT INTO Employee (firstName, lastName, salary) VALUES (\"Mike\", \"Chepesky\", 42000);");
sda.execute("INSERT INTO Employee (firstName, lastName, salary) VALUES (\"Westlee\", \"Barichak\", 55000);");
sda.execute("INSERT INTO Employee (firstName, lastName, salary) VALUES (\"Ian\", \"Dundas\", 47000);");
if(sda.hasError())
{
}
else
copyFileToAssetsFolder("quizz.db");
}
}
void SQLTest::copyFileToAssetsFolder(const QString fileName)
{
QString appFolder(QDir::homePath());
appFolder.chop(4);
QString originalFileName = appFolder + "app/native/assets/" + fileName;
QFile newFile(originalFileName);
// If I enable this `if` condition the code satisfies it and removes the quizz.db file and then it satisfies the next `if` condition and successfully copies the quizz.db file from `data` folder to `assets` folder.
/*if(newFile.exists())
QDir().remove(originalFileName);*/
// this `if` condition is not satisfied. Which should mean the quizz.db file has been created on assets folder.
if (!newFile.exists())
{
// If the file is not already in the assets folder, we copy it from the
// data folder (read and write) to the assets folder (read only).
QString dataFolder = QDir::homePath();
QString newFileName = dataFolder + "/" + fileName;
QFile originalFile(newFileName);
if (originalFile.exists())
{
// Create sub folders if any creates the SQL folder for a file path like e.g. sql/quotesdb
QFileInfo fileInfo(originalFileName);
QDir().mkpath (fileInfo.dir().path());
if(!originalFile.copy(originalFileName)) {
qDebug() << "Failed to copy file to path: " << originalFileName;
}
} else {
qDebug() << "Failed to copy file data base file does not exists.";
}
}
// mSourceInDataFolder = newFileName;
}
If I enable the commented if condition of copyFileToAssetsFolder function it removes already created quizz.db file in assets folder (which Im unable to find) and goes inside the next if condition and copies the quizz.db created on the data folder to assets fodler. But in any case I can't find the quizz.db in assets folder. I really need help with this quickly. Thanks.
Files in asset can not be modified
It seems its not possible to modify assets folder mentioned in here Now I am creating my db file in the data folder as it is writable.

Delete all files in a directory

I need to delete all files in a directory using Qt.
All of the files in the directory will have the extension ".txt".
I don't want to delete the directory itself.
Does anyone know how I can do this? I've looked at QDir but am having no luck.
Bjorns Answer tweeked to not loop forever
QString path = "whatever";
QDir dir(path);
dir.setNameFilters(QStringList() << "*.*");
dir.setFilter(QDir::Files);
foreach(QString dirFile, dir.entryList())
{
dir.remove(dirFile);
}
Ignoring the txt extension filtering... Here's a way to delete everything in the folder, including non-empty sub directories:
In QT5, you can use removeRecursively() on dirs. Unfortunately, that removes the whole directory - rather than just emptying it. Here is basic a function to just clear a directory's contents.
void clearDir( const QString path )
{
QDir dir( path );
dir.setFilter( QDir::NoDotAndDotDot | QDir::Files );
foreach( QString dirItem, dir.entryList() )
dir.remove( dirItem );
dir.setFilter( QDir::NoDotAndDotDot | QDir::Dirs );
foreach( QString dirItem, dir.entryList() )
{
QDir subDir( dir.absoluteFilePath( dirItem ) );
subDir.removeRecursively();
}
}
Alternatively, you could use removeRecursively() on the directory you want to clear (which would remove it altogether). Then, recreate it with the same name after that... The effect would be the same, but with fewer lines of code. This more verbose function, however, provides more potential for detailed exception handling to be added if desired, e.g. detecting access violations on specific files / folders...
Call QDir::entryList(QDir::Files) to get a list of all the files in the directory, and then for each fileName that ends in ".txt" call QDir::remove(fileName) to delete the file.
You started in a good way, look at entryList and of course pass the namefilter you want.
To improve on #user3191791's answer (which removes all files and directories), this answer:
Modernises the code with a range-based for loop
Provides optional error checking
The code:
struct FileOperationResult
{
bool success;
QString errorMessage;
};
FileOperationResult removeDirContents(const QString &dirPath)
{
QDir dir(dirPath);
dir.setFilter(QDir::NoDotAndDotDot | QDir::Files);
const QStringList files = dir.entryList();
for (const QString &fileName : files) {
if (!dir.remove(fileName)) {
const QString failureMessage = QString::fromUtf8(
"Failed to remove file %1 from %2").arg(fileName, dirPath);
return { false, failureMessage };
}
}
dir.setFilter(QDir::NoDotAndDotDot | QDir::Dirs);
const QStringList dirs = dir.entryList();
for (const QString &dirName : dirs) {
QDir subDir(dir.absoluteFilePath(dirName));
if (!subDir.removeRecursively()) {
const QString failureMessage = QString::fromUtf8(
"Failed to recursively remove directory %1 from %2").arg(dirName, dirPath);
return { false, failureMessage };
}
}
return { true, QString() };
}
Usage:
const FileOperationResult removeResult = removeDirContents(path);
if (!removeResult.success)
qWarning() << removeResult.errorMessage;
This is how I would do it:
QString path = "name-of-directory";
QDir dir(path);
dir.setNameFilters(QStringList() << "*.txt");
dir.setFilters(QDir::Files);
while(dir.entryList().size() > 0){
dir.remove(dir.entryList().first());
}
Other variant of rreeves's code:
QDir dir("/path/to/file");
dir.setNameFilters(QStringList() << "*.*");
dir.setFilter(QDir::Files);
for(const QString &dirFile: dir.entryList()) {
dir.remove(dirFile);
}
You can achieve this without using Qt: to do so, opendir, readdir, unlink, and even rmdir will be your friends. It's easy to use, just browse the man pages ;).