Есть ли функция Qt для перемещения файлов в корзину вместо того, чтобы действительно удалять их, для ОС, которые его поддерживают, или мне нужно использовать специфичный для ОС код?
API пока нет.
https://bugreports.qt.io/browse/QTBUG-181
Проблема закрыта, и версия исправления: Некоторый будущий выпуск
Редактировать: Новый выпуск был открыт на https://bugreports.qt.io/browse/QTBUG-47703.
Qt не предоставляет MoveToTrash. Вот часть моего кода
для Windows
#ifdef Q_OS_WIN32
#include "windows.h"
void MoveToTrashImpl( QString file ){
QFileInfo fileinfo( file );
if( !fileinfo.exists() )
throw OdtCore::Exception( "File doesnt exists, cant move to trash" );
WCHAR from[ MAX_PATH ];
memset( from, 0, sizeof( from ));
int l = fileinfo.absoluteFilePath().toWCharArray( from );
Q_ASSERT( 0 <= l && l < MAX_PATH );
from[ l ] = '\0';
SHFILEOPSTRUCT fileop;
memset( &fileop, 0, sizeof( fileop ) );
fileop.wFunc = FO_DELETE;
fileop.pFrom = from;
fileop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
int rv = SHFileOperation( &fileop );
if( 0 != rv ){
qDebug() << rv << QString::number( rv ).toInt( 0, 8 );
throw OdtCore::Exception( "move to trash failed" );
}
}
#endif
и для Linux
#ifdef Q_OS_LINUX
bool TrashInitialized = false;
QString TrashPath;
QString TrashPathInfo;
QString TrashPathFiles;
void MoveToTrashImpl( QString file ){
#ifdef QT_GUI_LIB
if( !TrashInitialized ){
QStringList paths;
const char* xdg_data_home = getenv( "XDG_DATA_HOME" );
if( xdg_data_home ){
qDebug() << "XDG_DATA_HOME not yet tested";
QString xdgTrash( xdg_data_home );
paths.append( xdgTrash + "/Trash" );
}
QString home = QStandardPaths::writableLocation( QStandardPaths::HomeLocation );
paths.append( home + "/.local/share/Trash" );
paths.append( home + "/.trash" );
foreach( QString path, paths ){
if( TrashPath.isEmpty() ){
QDir dir( path );
if( dir.exists() ){
TrashPath = path;
}
}
}
if( TrashPath.isEmpty() )
throw Exception( "Cant detect trash folder" );
TrashPathInfo = TrashPath + "/info";
TrashPathFiles = TrashPath + "/files";
if( !QDir( TrashPathInfo ).exists() || !QDir( TrashPathFiles ).exists() )
throw Exception( "Trash doesnt looks like FreeDesktop.org Trash specification" );
TrashInitialized = true;
}
QFileInfo original( file );
if( !original.exists() )
throw Exception( "File doesnt exists, cant move to trash" );
QString info;
info += "[Trash Info]\nPath=";
info += original.absoluteFilePath();
info += "\nDeletionDate=";
info += QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm:ss.zzzZ");
info += "\n";
QString trashname = original.fileName();
QString infopath = TrashPathInfo + "/" + trashname + ".trashinfo";
QString filepath = TrashPathFiles + "/" + trashname;
int nr = 1;
while( QFileInfo( infopath ).exists() || QFileInfo( filepath ).exists() ){
nr++;
trashname = original.baseName() + "." + QString::number( nr );
if( !original.completeSuffix().isEmpty() ){
trashname += QString( "." ) + original.completeSuffix();
}
infopath = TrashPathInfo + "/" + trashname + ".trashinfo";
filepath = TrashPathFiles + "/" + trashname;
}
QDir dir;
if( !dir.rename( original.absoluteFilePath(), filepath ) ){
throw Exception( "move to trash failed" );
}
File infofile;
infofile.createUtf8( infopath, info );
#else
Q_UNUSED( file );
throw Exception( "Trash in server-mode not supported" );
#endif
}
#endif
Я думаю, что нет кроссплатформенного пути. Простое перемещение файлов в «мусорную корзину» не даст эффекта, потому что пользователь может отключить эту возможность.
Может быть, этот URL поможет: http://www.hardcoded.net/articles/send-files-to-trash-on-all-platforms.htm
Я относительно уверен, что не существует API Qt, который оборачивает это для всех поддерживаемых платформ. К сожалению, это означает, что вам придется писать код для конкретной платформы.
Я ничего не знаю о том, где и как дистрибутивы Linux хранят удаленные файлы, и я предполагаю, что это, вероятно, зависит от того, какой файловый менеджер вы используете. Я считаю, что перемещение файлов в ~/.Trash
папка является стандартным способом сделать это, но я не уверен, что это надежно. Например, в случае файлов, хранящихся на внешних томах.
В Mac OS X все немного проще, и для этого есть поддерживаемый API: FSMoveObjectToTrashSync
, предоставляемых Core Services. По крайней мере, я так помню, ты должен это делать. Документация утверждает, что этот метод в настоящее время устарел в OS X 10.8. Я понятия не имею, что является рекомендуемой альтернативой.
Как программист Windows, я думаю, что эта платформа намного проще. 🙂 Основным решением является вызов SHFileOperation
функция:
#include <Windows.h> // general Windows header file
#include <ShellAPI.h> // for shell functions, like SHFileOperation
#include <string> // (or use QString)
void RecycleFileOnWindows()
{
std::wstring path = L"C:\\Users\\Administrator\\Documents\\deleteme.txt";
path.append(1, L'\0'); // path string must be double nul-terminated
SHFILEOPSTRUCT shfos = {};
shfos.hwnd = nullptr; // handle to window that will own generated windows, if applicable
shfos.wFunc = FO_DELETE;
shfos.pFrom = path.c_str();
shfos.pTo = nullptr; // not used for deletion operations
shfos.fFlags = FOF_ALLOWUNDO; // use the recycle bin
const int retVal = SHFileOperation(&shfos);
if (retVal != 0)
{
// The operation failed...
if (shfos.fAnyOperationsAborted)
{
// ...but that's because the user canceled.
MessageBox(nullptr, L"Operation was canceled", nullptr, MB_OK | MB_ICONINFORMATION);
}
else
{
// ...for one of the other reasons given in the documentation.
MessageBox(nullptr, L"Operation failed", nullptr, MB_OK | MB_ICONERROR);
}
}
}
Есть также флаги, которые вы можете установить, чтобы настроить подтверждение, отчеты об ошибках и другое поведение. Связанная документация содержит все детали, необходимые для построения этого базового примера.
В Windows Vista и более поздних SHFileOperation
функция была заменена методами, предоставленными IFileOperation
интерфейс. Если вы ориентируетесь только на эти более поздние версии Windows, вам следует использовать этот интерфейс. Иначе, SHFileOperation
продолжит работать нормально.
if(QSysInfo::kernelType()=="linux")
{
QDateTime currentTime(QDateTime::currentDateTime()); // save System time
QString trashFilePath=QDir::homePath()+"/.local/share/Trash/files/"; // trash file path contain delete files
QString trashInfoPath=QDir::homePath()+"/.local/share/Trash/info/"; // trash info path contain delete files information
// create file format for trash info file----- START
QFile infoFile(trashInfoPath+FileName.completeBaseName()+"."+FileName.completeSuffix()+".trashinfo"); //filename+extension+.trashinfo // create file information file in /.local/share/Trash/info/ folder
infoFile.open(QIODevice::ReadWrite);
QTextStream stream(&infoFile); // for write data on open file
stream<<"[Trash Info]"<<endl;
stream<<"Path="+QString(QUrl::toPercentEncoding(FileName.absoluteFilePath(),"~_-./"))<<endl; // convert path string in percentage decoding scheme string
stream<<"DeletionDate="+currentTime.toString("yyyy-MM-dd")+"T"+currentTime.toString("hh:mm:ss")<<endl; // get date and time format YYYY-MM-DDThh:mm:ss
infoFile.close();
// create info file format of trash file----- END
QDir file;
file.rename(FileName.absoluteFilePath(),trashFilePath+FileName.completeBaseName()+"."+FileName.completeSuffix()); // rename(file old path, file trash path)}
Мусорные файлы в Linux существуют /home/user_name/.local/share/Trash/files/
каталог, но он также требует информационный файл для каждого файла корзины, которые существуют в /home/user_name/.local/share/Trash/info/
каталог. когда мы хотим переместить файл в корзину, на самом деле переместить файл в /home/user_name/.local/share/Trash/files/
каталог и создать информационный файл в /home/user_name/.local/share/Trash/info/
каталог. внутри .trashinfo Формат использует процентную схему декодирования для задания пути к файлу, в котором файл существует, в информационном файле также указывается время и дата удаления.