【问题标题】:Move files to Trash/Recycle Bin in Qt在 Qt 中将文件移动到垃圾箱/回收站
【发布时间】:2013-07-31 07:42:06
【问题描述】:

对于支持它的操作系统,是否有 Qt 函数可以将文件移动到回收站而不是真正删除它们,还是我需要使用操作系统特定的代码?

【问题讨论】:

标签: c++ qt cross-platform recycle-bin


【解决方案1】:

Qt 5.15.0 Alpha开始,添加了这个方法,应该就是你要找的。​​p>

bool QFile::moveToTrash()

对应的代码改动可以在here找到。

(这个问题很老了,https://bugreports.qt.io/browse/QTBUG-47703 的相应 Bugreport 已经发布,但我目前缺乏评论的声誉,发现这是一个有用的信息。)

【讨论】:

    【解决方案2】:

    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
    

    【讨论】:

      【解决方案3】:

      还没有 API。

      https://bugreports.qt.io/browse/QTBUG-181

      问题已关闭,修复版本为:某个未来版本

      编辑:一个新问题已在https://bugreports.qt.io/browse/QTBUG-47703打开。

      编辑显然它现在已在 5.15.0 Alpha bool QFile::moveToTrash()

      中完成

      【讨论】:

      • 奇怪的问题处理。关闭为...?不会修?太难?通常,当答案是“也许以后”时,问题就悬而未决。
      • 有一个新问题在这里重新打开了这个旧问题:bugreports.qt.io/browse/QTBUG-47703
      • 更新:移动到垃圾箱应该在 Qt 5.15 中实现。
      【解决方案4】:

      我认为没有跨平台的方式。简单地将文件移动到“垃圾”位置不会生效,因为用户可能会关闭这种可能性。

      也许,这个网址会有所帮助:http://www.hardcoded.net/articles/send-files-to-trash-on-all-platforms.htm

      【讨论】:

      • 这篇文章适用于 Python,但不适用于 C++。
      • @sashoalm 这篇文章是关于使用的 API 的。用什么语言称呼它们并不重要。
      【解决方案5】:

      我比较确定没有 Qt API 可以为所有受支持的平台包装它。不幸的是,这意味着您将不得不编写特定于平台的代码。

      我对 Linux 发行版在何处/如何存储已删除文件一无所知,我想这可能会因您使用的文件管理器而异。我相信将文件移动到~/.Trash 文件夹是标准的做法,但我不确定这是否可靠。例如,对于存储在外部卷上的文件。

      Mac OS X 上的事情要容易一些,它有一个支持的 API 来执行此操作:FSMoveObjectToTrashSync,由 Core Services 提供。至少,这就是我记得你应该这样做的方式。 The documentation 声称此方法现在在 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 将继续正常工作。

      【讨论】:

      • 在 Linux 上,FreeDesktop.org Trash specification 似乎在谈论文件存储在外部卷上的情况。许多流行的 Linux 文件管理器都支持它,包括 Nautilus 和 Dolphin。
      • 或者 Qt 的人可能是务实的,只是为 Ubuntu 和接下来的 1-2 个最流行的发行版实现它。
      【解决方案6】:
      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)
      
      
      
      }
      

      【讨论】:

      • 欢迎来到stackoverflow。请解释一下您的回答。
      • 注意QSysInfo::kernelType()=="linux",Android的内核也是Linux。
      【解决方案7】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-07-05
        • 1970-01-01
        • 2014-06-18
        • 2018-06-08
        • 2011-04-07
        • 1970-01-01
        • 2011-10-10
        • 1970-01-01
        相关资源
        最近更新 更多