【大話QT之五】Windows與Linux下檔案操作監控的實現__Linux

來源:互聯網
上載者:User

一、需求分析:

        隨著渲染業務的不斷進行,資料轉送漸漸成為影響業務時間最大的因素。究其原因就是因為資料轉送耗費較長的時間。於是,依託於渲染業務的網盤開發逐漸成為迫切需要解決的需求。該網盤的實現和當前市場上網盤實現有一些的不同,主要在用戶端與伺服器端的操作需要雙向進行,即:使用者在用戶端的操作需要及時同步到伺服器端;在伺服器端作業渲染產生的檔案要及時同步到用戶端。即:使用者不在需要單獨的下載資料,而是在作業啟動並執行同時,渲染就過就會自動同步到用戶端,大大縮短了等待時間。當然,無論是在用戶端還是在服務端都面臨著一個問題,即:實現對檔案操作的監控,這裡的檔案操作包括:檔案(夾)建立、檔案(夾)刪除、檔案(夾)重新命名、檔案(夾)移動等操作。除此之外還要能夠同步用戶端檔案的修改操作,即:當使用者退出網盤後,修改了原有同步目錄中的檔案,當使用者再次啟動網盤時通過一次掃描與md5值的比較能缺確定出哪些檔案發生了改動,並將改動後的操作及時同步到服務端。這裡,先將Windows(用戶端實現需要)與Linux(服務端實現需要)下檔案監控的實現方法簡要概述。

二、檔案監控實現方法分析

      1> Windows下檔案監控的實現

            Windows下實現檔案監控的原理是利用SHChangeNotifyRegister把指定的視窗添加到系統的訊息監視鏈中,從而註冊視窗就可以接收到來自檔案系統或Shell的通知了。在繼續向下說明之前,需要解釋一下Windows外殼名字空間(Shell Name Space)的概念。

            外殼名字空間是Windows下的標準檔案系統,它大大擴充了Dos檔案系統,形成了以”案頭“為根的單一檔案系統樹,原有的C、D盤等分類樹變成了“我的電腦”這一外殼名字控制項子樹的下一級子樹,而像“控制台”、“資源回收筒”、“網路位置”等應用程式以及“印表機”等裝置也被虛擬成了外殼名字空間中的節點。為了區別於Dos中“目錄”的概念,Windows引入了“檔案夾”的概念。“檔案夾”一般是指外殼名字空間樹中的非葉幾點,既可以是DOS下的目錄,也可以是“控制台”、“資源回收筒”這類虛擬目錄。

            新的“路徑”PIDL:外殼物件識別碼列表。PIDL是一個元素類型為ITEMIDLIST結構的數組,數組中元素的個數是未知的,但緊接著數組的末尾的必是一個雙位元組的零。每個數組元素代表了外殼名字空間樹中的一層(即一個檔案夾或檔案),數組中的前一元素代表的是後一元素的父資料夾。由此可見,PIDL實際上就是指向一塊由若干個順序排列的ITEMIDLIST結構組成、並在最後有一個雙位元組零的空間的指標。所以PIDL的類型就被Windows定義為ITEMIDLIST結構的指標。

            DOS中的路徑是一個字串,但PIDL是一種二進位結構,所以我們不能直接從PIDL中獲知它所代表的到底是哪個檔案夾或檔案,而必須調用相應的函數把它轉換為代表路徑的字串。如果某絕對PIDL是檔案系統的一部分,則調用SHGetPathFromIDList函數即可;但如不是,就無法獲得路徑字串了,因為DOS中根本就不存在這種路徑。

       總體來說:實現Windows下檔案監控的基本流程如下:

              

       上圖是在windows下利用C++實現檔案監控的一種方式(根據需要靈活改動),這裡簡要敘述一下:1) 利用DialogBoxParam建立一個模態對話方塊,進入視窗過程函數,在該視窗函數中根據各種訊息來完成我們的操作。這裡模態對話方塊與非模態對話方塊的區別之一是因為它有一套自己的訊息泵機制,不需要我們再手動寫訊息的接收了(非模態對話方塊要自己接收訊息)。攔截使用者訊息,根據各個不同的階段可以加入我們自己的操作,比如初始化等。2) 擷取指定路徑的PIDL:即目標路徑的外殼物件識別碼,有了它才能繼續後續的處理,這裡的擷取有兩種方式,一種是利用IFileDialog開啟對話方塊讓使用者選擇(IFileDialog *pfd),從而通過GetResult(IShellItem *psi ; pfs->GetResult(&psi))擷取IShellItem對象;然後利用QueryInterface(IShellItem2 *_psiDrop ; psi->QueryInterface(&_psiDrop))擷取IShellItem2對象;最後利用它就可以獲得PIDL了(利用SHGetIDListFromObject)。3) 最後利用SHChangeNotifyRegister完成最終目標表單的掛載,從而將一個目錄加入到系統的訊息鏈中,從而可以擷取檔案系統或Shell中關於檔案操作的相關資訊。最後將資訊解析出來就可以了。

       還有一種方式即直接提供目標檔案夾的絕對路徑,由該路徑擷取到PIDL,從而將表單掛載到系統訊息鏈中,注意:如果是在QT中實現的話,可以很輕鬆的擷取到QWidget的視窗控制代碼。關鍵代碼如下:

void houqd::RegisterWindow(){char absoluteFolderPath[] = "C:\\openssl";//! 由檔案夾的絕對路徑擷取PIDL:外殼物件識別碼列表,即在windows 外殼名字空間 "Shell Name Space"中的表示方法。LPITEMIDLIST myFolderPIDL = ParsePidlFromPath(absoluteFolderPath);HRESULT res ;IShellItem *psi = NULL;//! 建立一個IShellItem(interface)對象,IShellItem interface提供了尋找一個關於Shell Item相關資訊的方法。//! IShell Item介面都繼承自IUnknown interfaceres = SHCreateShellItem(NULL, NULL, myFolderPIDL, &psi);IShellItem2 *ppsi ;//! 檢索一個對象上支援的介面的指標psi->QueryInterface(&ppsi);//! =======================================註冊檔案監控=============================================PIDLIST_ABSOLUTE pidlWatch;HRESULT hr = SHGetIDListFromObject(ppsi, &pidlWatch);if(SUCCEEDED(hr)){SHChangeNotifyEntry const entries[] = { pidlWatch, true };int const nSources = SHCNRF_ShellLevel | SHCNRF_InterruptLevel | SHCNRF_NewDelivery;//! 註冊視窗主函數_ulRegister = SHChangeNotifyRegister(_hdlg, nSources, SHCNE_ALLEVENTS, c_notifyMessage, ARRAYSIZE(entries), entries);hr = _ulRegister != 0 ? S_OK : E_FAIL;}//ShowWindow(SW_HIDE);//! ====================================================================================}
ParsePidFromPath 的具體實現如下:

LPITEMIDLIST houqd::ParsePidlFromPath(LPCSTR lpszPath){//存放以Unicode內碼錶示的路徑字串的緩衝區 OLECHAR szOleChar[MAX_PATH]; //“案頭“的IshellFolder介面指標 LPSHELLFOLDER lpsfDeskTop; //返回的PIDL LPITEMIDLIST lpifq; ULONG ulEaten, ulAttribs; HRESULT hres; //得到“案頭”的IshellFolderr 介面指標 SHGetDesktopFolder(&lpsfDeskTop); //將Ansi字元集的路徑字串轉換成Unicode字串,存入szOleChar MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED, lpszPath, -1, szOleChar, sizeof(szOleChar)); //將szOleChar,中的路徑徑字串翻譯成相應的PIDL,存入lpifq hres = lpsfDeskTop->ParseDisplayName(NULL, NULL, szOleChar, &ulEaten, &lpifq, &ulAttribs); hres = lpsfDeskTop->Release(); //如果翻譯失敗,則返回NULL if(FAILED(hres))  return NULL; return lpifq;}

      2> Linux下檔案監控的實現

        Linux下主要是通過inotify實現檔案監控。它是一個核心使用者通知使用者空間程式檔案系統變化的機制。在使用者狀,inotify通過三個系統調用和在返回的檔案描述符上的檔案I/O操作來使用.

        1) 使用inotify的第一步是建立inotify的執行個體:int fd = inotify_init() ; 每一個inotify執行個體對應一個獨立的排序的隊列。

        2) int wd = inotify_add_watch(fd , file_dir_path , mask);添加一個目錄的監控。

        3) 刪除一個監控:inotify_rm_watch(fd , wd);

       關鍵代碼如下:

if (m_InotifyFd != LHFSMC_FD_UNCREATED_STATE)        close(m_InotifyFd);    //! inotify_init()    if ((m_InotifyFd = inotify_init()) < 0)    {        qDebug() << "[error] LHFileSystemMonitor::Start: inotify_init failure.";        return 0;    }    //! 為m_CreatedDirList中所有儲存的目錄建立監控    if(!CreateWatcherForEachDir(m_CreatedDirList))    {        qDebug() << "[error] LHFileSystemMonitor::Start: CreateNotifierForEachDir failure.";        return 0;    }
CreateWatcherForEachDir的實現:

int LHFileSystemMonitor::CreateWatcherForEachDir(QStringList &dirLocationList){#ifndef WIN32    for (QStringList::const_iterator iter = dirLocationList.begin();         iter != dirLocationList.end();         ++iter)    {        int watchDescriptor;        if ((watchDescriptor = CreateWatcher(iter->toStdString().c_str())) > 0)            m_MonitoredObjectList.push_back(LHFSMonitorData(*iter, watchDescriptor));        else            qDebug() << "[error] LHFileSystemMonitor::CreateWatcherForEachDir: CreateWatcher for"                     << *iter << "failure";    }#endif    return 1;}
CreateWatcher的實現:

int LHFileSystemMonitor::CreateWatcher(const char *fileLocation) const{    if (fileLocation == NULL)        return 0;    QDir dir(fileLocation);    if (!dir.exists())    {        qDebug() << "[error] LHFileSystemMonitor::CreateNotifier:" << fileLocation << "is not exist!";        return 0;    }    return ((m_InotifyFd != LHFSMC_FD_UNCREATED_STATE) ? inotify_add_watch(m_InotifyFd, fileLocation, LHFSMC_MONITOR_EVENT) : -1);}
總結:

        以上就是Windows以及Linux下檔案監控系統實現的相關思路及代碼,僅僅作為一個引入,利用這種方式均可以實現對應的功能。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.