管理檔案系統

Shell 提供數種方式來管理檔案系統。 Shell 提供函式 SHFileOperation,可讓應用程式以程式設計方式移動、複製、重新命名和刪除檔案。 Shell 也支援一些額外的檔案管理功能。

  • HTML 檔案可以 連接到 相關的檔案,例如圖形檔案或樣式表單。 移動或複製檔時,也會自動移動或複製連接的檔案。
  • 對於一個以上的使用者可用的系統,可以個別管理檔案。 使用者可以輕鬆地存取其資料檔案,但無法存取屬於其他使用者的檔案。
  • 如果新增或修改檔檔,則可以將它們新增至命令介面的最近檔案清單。 當使用者按一下 [開始] 功能表上的 [ ] 命令時,會顯示檔的連結清單。

本檔討論這些檔案管理技術的運作方式。 然後概述如何使用殼層來移動、複製、重新命名和刪除檔案,以及如何管理回收站中的物件。

Per-User檔案管理

Windows 2000 Shell 允許與特定使用者建立關聯的檔案,讓檔案與其他使用者保持隱藏。 就檔案系統而言,這些檔案會儲存在使用者設定檔資料夾底下,通常是 Windows 2000 系統上的 C:\Documents and Settings\Username\ 。 此功能可讓許多個人使用相同的電腦,同時維護其他使用者檔案的隱私權。 不同的使用者可以有不同的程式可供使用。 它也可讓系統管理員和應用程式直接儲存初始化 (.ini) 或連結 (.lnk) 檔案等專案。 因此,應用程式可以保留每個使用者的不同狀態,並在需要時輕鬆地復原該特定狀態。 也有設定檔資料夾可用來儲存所有使用者通用的資訊。

由於判斷登入的使用者及其檔案所在的位置很不方便,因此標準個別使用者資料夾是特殊資料夾,並由 CSIDL識別。 例如,個別使用者 Program Files 資料夾的 CSIDL 會CSIDL_PROGRAMS。 如果您的應用程式使用其中一個每個使用者 CSIDL 呼叫 SHGetFolderLocationSHGetFolderPath ,此函式會傳回 PIDL 清單的指標 (PIDL) 或目前登入使用者適用的路徑。 如果您的應用程式需要擷取設定檔資料夾的路徑或 PIDL,則會 CSIDL_PROFILE其 CSIDL。

我的檔和我的圖片資料夾

在桌面上找到的其中一個標準圖示是 [我的檔]。 當您開啟此資料夾時,它會包含目前使用者的檔檔。 我的檔桌面實例是虛擬資料夾,這是用來實際儲存使用者檔的檔案系統位置別名,位於命名空間階層中的桌面正下方。

[我的檔] 和 [我的圖片] 資料夾的目的是提供簡單且安全的方式,讓使用者在可能有多個使用者的系統上存取其檔和圖片檔案。 每位使用者都會為其檔案指派個別的檔系統資料夾。 例如,使用者的檔資料夾在檔案系統中的位置通常是 C:\Documents 和 Settings\username\My Documents。 使用者不需要知道其檔系統資料夾實體位置的任何專案。 他們只要透過 [我的檔] 圖示存取其檔案。

注意

我的檔可讓使用者存取自己的檔案,但不能存取任何其他使用者的檔案。 如果多個人員使用相同的電腦,系統管理員可以將使用者鎖定儲存實際檔案的檔案系統部分。 因此,使用者將能夠透過 [我的文件] 資料夾處理自己的檔,但無法處理屬於任何其他使用者的檔。

 

應用程式通常不需要知道哪個使用者已登入,或使用者 [我的文件] 資料夾所在的檔案系統位置。 相反地,您的應用程式可以藉由呼叫桌面的 IShellFolder::P arseDisplayName 方法來擷取我的文件桌面圖示的 PIDL。 用來識別 [我的文件] 資料夾的剖析名稱不是檔案路徑,而是 ::{450d8fba-ad25-11d0-98a8-0800361b1103}。 方括號運算式是 My Documents GUID 的文字形式。 例如,若要擷取 My Documents 的 PIDL,您的應用程式應該使用此 IShellFolder::P arseDisplayName的呼叫。

hr = psfDeskTop->ParseDisplayName(NULL, 
                                  NULL, 
                                  L"::{450d8fba-ad25-11d0-98a8-0800361b1103}", 
                                  &chEaten, 
                                  &pidlDocFiles, 
                                  NULL);

一旦您的應用程式擁有 My Documents PIDL,它就可以處理資料夾,就像是一般的檔系統資料夾一樣,列舉專案、剖析、系結,以及執行任何其他有效的資料夾作業。 Shell 會自動將 [我的檔] 或其子資料夾中的變更對應至適當的檔系統資料夾。

如果您的應用程式需要存取包含目前使用者檔的實際檔系統資料夾,請將CSIDL_PERSONAL傳遞給 SHGetFolderLocation。 函式會傳回目前使用者 [我的文件] 資料夾中所顯示的檔系統資料夾 PIDL。

已連線的檔案

HTML 檔案通常有許多相關聯的圖形檔案、樣式表單檔案、數個 Microsoft JScript (與 ECMA 262 語言規格相容) 檔案等等。 當您移動或複製主要 HTML 檔案時,您通常也會想要移動或複製其相關聯的檔案,以避免中斷連結。 可惜的是,到目前為止,無法輕易判斷哪些檔案與任何指定的 HTML 檔案有關,而不是藉由分析其內容。 為了減輕這個問題,Windows 2000 提供將主要 HTML 檔案連線到其相關聯檔案群組的簡單方式。 如果已啟用檔案連線,當檔移動或複製其所有已連線的檔案時,會與其一起移動。

若要建立連線的檔案群組,主要檔必須具有.htm或.html副檔名。 建立主文件父資料夾的子資料夾。 子資料夾的名稱必須是主要檔的名稱,減去.htm或.html副檔名,後面接著下列其中一個延伸模組。 最常使用的副檔名為 「.files」 或 「_files」。 例如,如果主要檔命名為 MyDoc.htm,命名子資料夾 「MyDoc_files」 會將子資料夾定義為檔連線檔案的容器。 如果移動或複製主文件,子資料夾及其檔案也會移動或複製。

對於某些語言,可以使用當地語系化的對等 「_files」 來建立連線檔案的子資料夾。 下表列出可附加至檔案名稱的有效字串,以建立連接的檔案子資料夾。 請注意,其中有些字串具有 '-' 作為其第一個字元,而不是 '_' 或 '.'。

「_archivos」

「_arquivos」

「_bestanden」

「_bylos」

「-Dateien」

「_datoteke」

「_dosyalar」

「_elemei」

「_failid」

「_fails」

「_fajlovi」

「_ficheiros」

「_fichiers」

「-filer」

「.files」

「_files」

「_file」

「_fitxers」

「_fitxategiak」

「_pliki」

「_soubory」

「_tiedostot」

 

注意

這項功能會區分擴充功能的大小寫。 例如,針對上述範例,名為 「MyDoc_Files」 的子資料夾將不會連線到MyDoc.htm。

 

是否啟用或停用檔案連線是由 下列登錄機碼的 REG_DWORD 值 NoFileFolderConnection 所控制。

HKEY_CURRENT_USER
   Software
      Microsoft
         Windows
            CurrentVersion
               Explorer

此值通常未定義,且已啟用檔案連線。 如有必要,您可以將此值新增至機碼並將其設定為 1,以停用檔案連線。 若要再次啟用檔案連線,請將 NoFileFolderConnection 設定為零。

注意

通常應該啟用檔案連線,因為其他應用程式可能會相依于它。 只有在絕對必要時才停用檔案連線。

 

移動、複製、重新命名和刪除檔案

命名空間不是靜態的,而且應用程式通常需要執行下列其中一項作業來管理檔案系統。

  • 將物件複製到另一個資料夾。
  • 將物件移至另一個資料夾。
  • 刪除物件。
  • 重新命名物件。

這些作業全都是使用 SHFileOperation來執行。 此函式會接受一或多個來源檔案,並產生對應的目的地檔案。 在刪除作業的情況下,系統會嘗試將已刪除的檔案放入回收站。

您也可以使用 拖放 功能來移動檔案。

若要使用 函式,您必須填入 SHFILEOPSTRUCT 結構的成員,並將它傳遞至 SHFileOperation。 結構的索引鍵成員是 pFrompTo

pFrom成員是包含一或多個來原始檔案名的雙Null終止字串。 這些名稱可以是完整路徑或標準 DOS 萬用字元,例如 *.*。 雖然這個成員宣告為 以 Null結尾的字串,但它會當做緩衝區來保存多個檔案名。 每個檔案名都必須以一般單 一 Null 字元終止。 額外的 Null 字元必須附加至最終名稱的結尾,以指出 pFrom的結尾。

pTo成員是雙null終止的字串,非常類似pFrompTo成員包含一或多個完整目的地名稱的名稱。 它們會以pFrom的相同方式封裝到pTo中。 如果pTo包含多個名稱,您也必須在fFlags成員中設定FOF_MULTIDESTFILES旗標。 pTo的使用方式取決於作業,如這裡所述。

  • 針對複製和移動作業,如果所有檔案都移至單一目錄, pTo 會包含完整目錄名稱。 如果檔案前往不同的目的地, pTo 也可以包含每個來源檔案的一個完整目錄或檔案名。 如果目錄不存在,系統會建立目錄。
  • 針對重新命名作業, pTo 會針對 pFrom中的每個原始程式檔包含一個完整路徑。
  • 針對刪除作業,不會使用 pTo

通知殼層

使用 SHFileOperation 移動、複製、重新命名或刪除檔案之後,或在採取任何其他會影響命名空間的動作之後,通知殼層變更。 應該伴隨通知的動作包括下列各項:

  • 新增或刪除檔案或資料夾。
  • 移動、複製或重新命名檔案或資料夾。
  • 變更檔案關聯。
  • 變更檔案屬性。
  • 新增或移除磁片磁碟機或儲存媒體。
  • 建立或停用共用資料夾。
  • 變更系統映射清單。

應用程式會呼叫 SHChangeNotify 來通知殼層,其中包含已變更專案的詳細資料。 接著,Shell 可以更新命名空間的映射,以正確反映其新狀態。

使用 SHFileOperation 管理檔案的簡單範例

下列範例主控台應用程式說明如何使用 SHFileOperation 將檔案從一個目錄複寫到另一個目錄。 為了簡單起見,來源和目的地目錄 C:\My_Docs 和 C:\My_Docs2會硬式編碼到應用程式中。

#include <shlobj.h>
#include <shlwapi.h>
#include <strsafe.h>

int main(void)
{
    IShellFolder *psfDeskTop = NULL;
    IShellFolder *psfDocFiles = NULL;
    LPITEMIDLIST pidlDocFiles = NULL;
    LPITEMIDLIST pidlItems = NULL;
    IEnumIDList *ppenum = NULL;
    SHFILEOPSTRUCT sfo;
    STRRET strDispName;
    TCHAR szParseName[MAX_PATH];
    TCHAR szSourceFiles[256];
    int i;
    int iBufPos = 0;
    ULONG chEaten;
    ULONG celtFetched;
    size_t ParseNameSize = 0;
    HRESULT hr;
    

    szSourceFiles[0] = '\0';
    hr = SHGetDesktopFolder(&psfDeskTop);

    hr = psfDeskTop->ParseDisplayName(NULL, NULL, L"c:\\My_Docs", 
         &chEaten, &pidlDocFiles, NULL);
    hr = psfDeskTop->BindToObject(pidlDocFiles, NULL, IID_IShellFolder, 
         (LPVOID *) &psfDocFiles);
    hr = psfDeskTop->Release();

    hr = psfDocFiles->EnumObjects(NULL,SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, 
         &ppenum);

    while( (hr = ppenum->Next(1,&pidlItems, &celtFetched)) == S_OK 
       && (celtFetched) == 1)
    {
        psfDocFiles->GetDisplayNameOf(pidlItems, SHGDN_FORPARSING, 
            &strDispName);
        StrRetToBuf(&strDispName, pidlItems, szParseName, MAX_PATH);
        
        hr = StringCchLength(szParseName, MAX_PATH, &ParseNameSize);
        
        if (SUCCEEDED(hr))
        {
            for(i=0; i<=ParseNameSize; i++)
            {
                szSourceFiles[iBufPos++] = szParseName[i];
            }
            CoTaskMemFree(pidlItems);
        }
    }
    ppenum->Release();
    
    szSourceFiles[iBufPos] = '\0';

    sfo.hwnd = NULL;
    sfo.wFunc = FO_COPY;
    sfo.pFrom = szSourceFiles;
    sfo.pTo = "c:\\My_Docs2\0";
    sfo.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;

    hr = SHFileOperation(&sfo);
    
    SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, (LPCVOID) "c:\\My_Docs2", 0);

    CoTaskMemFree(pidlDocFiles);
    psfDocFiles->Release();

    return 0;
}

應用程式會先擷取桌面 IShellFolder 介面的指標。 然後,它會將來原始目錄的完整路徑傳遞至 IShellFolder::P arseDisplayName,以擷取來原始目錄的 PIDL。 請注意, IShellFolder::P arseDisplayName 需要目錄的路徑為 Unicode 字串。 應用程式接著會系結至來原始目錄,並使用其 IShellFolder 介面來擷取列舉值物件的 IEnumIDList 介面。

當列舉來原始目錄中的每個檔案時, 會使用 IShellFolder::GetDisplayNameOf 來擷取其名稱。 已設定SHGDN_FORPARSING旗標,這會導致 IShellFolder::GetDisplayNameOf 傳回檔案的完整路徑。 包含終止 Null 字元的檔案路徑會串連成單一陣列 szSourceFiles。 第二個 Null 字元會附加至最後一個路徑,以正確終止陣列。

列舉完成後,應用程式會將值指派給 SHFILEOPSTRUCT 結構。 請注意,指派給 pTo 的陣列也必須以雙 Null終止目的地。 在此情況下,它只會包含在指派給 pTo的字串中。 因為這是主控台應用程式,所以FOF_SILENT、FOF_NOCONFIRMATION和FOF_NOCONFIRMMKDIR旗標會設定為隱藏任何可能會出現的對話方塊。 SHFileOperation傳回之後,會呼叫SHChangeNotify通知殼層變更。 然後,應用程式會執行一般清除並傳回。

將檔案新增至殼層最近使用的檔案清單

Shell 會維護每個使用者最近新增或修改的檔案清單。 使用者可以按一下 [開始] 功能表上的 [檔] 來顯示這些檔案的連結清單。 如同我的檔,每個使用者都有檔案系統目錄來保存實際的連結。 若要擷取目前使用者最近目錄的 PIDL,您的應用程式可以使用 CSIDL_RECENT 呼叫SHGetFolderLocation,或呼叫 SHGetFolderPath來擷取其路徑。

您的應用程式可以使用本檔稍早討論的技術,列舉 [最近] 資料夾的內容。 不過,應用程式不應該修改資料夾的內容,就像是一般檔系統資料夾一樣。 如果這樣做,Shell 最近的檔案清單將不會正確更新,而且變更不會反映在 [開始] 功能表中。 相反地,若要將檔連結新增至使用者的 [最近] 資料夾,您的應用程式可以呼叫 SHAddToRecentDocs。 Shell 會將連結新增至適當的檔系統資料夾,以及更新其最近檔和 [開始] 功能表的清單。 您也可以使用此函式來清除資料夾。