在Qt中将文件移动到垃圾桶/回收站

20

在支持回收站功能的操作系统中,是否有Qt函数可用于将文件移动到回收站而非真正删除它们,或者我需要使用特定于操作系统的代码?


就像下面 @darthn 的回答所说的那样,Qt 5.15 中添加了 QFile.moveToTrash(参见公告)。希望这可以帮到你! - sunyata
7个回答

9

Qt 5.15.0 Alpha版本开始,已添加了此方法,这应该是您正在寻找的内容。

bool QFile::moveToTrash()

这些相关的代码更改可以在这里找到。

(这个问题是旧的,相应的Bugreport已经发布在https://bugreports.qt.io/browse/QTBUG-47703,但我目前缺少发表评论的声誉,并且认为这些信息很有用。)


8
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

5

3
奇怪的问题处理。关闭为...?不修复?太难了?通常情况下,当答案是“以后再说”时,问题只是保持开放状态。 - Cody Gray
1
这里有一个新问题重新打开了旧问题:https://bugreports.qt.io/browse/QTBUG-47703 - Felix
1
更新:将移动到垃圾桶的功能应该在Qt 5.15中实现。 - HiFile.app - best file manager

3

我相信在所有支持的平台上都没有一个Qt API来包装这个功能。这意味着不幸的是,您将不得不编写特定于平台的代码。

我不知道Linux发行版存储已删除文件的任何信息,并且我想这可能取决于您使用哪个文件管理器。我相信将文件移动到~/.Trash文件夹是标准方法,但我不确定这是否可靠。例如,在外部卷中存储的文件的情况下。

在Mac OS X上,情况要容易一些,因为有一个受支持的API可以实现这一点:由Core Services提供的FSMoveObjectToTrashSync。至少,我记得你应该这样做。 文档声称此方法现在在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仍将正常工作。


2
在Linux上,有FreeDesktop.org垃圾规范,它似乎涉及存储在外部卷上的文件的情况。它得到了许多流行的Linux文件管理器的支持,包括Nautilus和Dolphin。 - silviubogan
或者Qt的开发人员可以很实际地只为Ubuntu和接下来最受欢迎的1-2个发行版实现它。 - sashoalm

3

这篇文章是关于Python的,不是关于C++的。 - sashoalm
2
@sashoalm 这篇文章是关于使用的API的。无论从哪种语言调用它们都没有关系。 - Dmitry Sazonov

1
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)



}

1
欢迎来到stackoverflow。请解释一下你的答案。 - Rohan Khude
只需小心使用 QSysInfo::kernelType()=="linux",因为Android的内核也是Linux。 - sashoalm

1
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格式中,使用百分比解码方案来设置文件所在的路径,信息文件还包含删除的时间和日期。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接