管理檔案系統
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 呼叫 SHGetFolderLocation 或 SHGetFolderPath ,此函式會傳回 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。 結構的索引鍵成員是 pFrom 和 pTo。
pFrom成員是包含一或多個來原始檔案名的雙Null終止字串。 這些名稱可以是完整路徑或標準 DOS 萬用字元,例如 *.*。 雖然這個成員宣告為 以 Null結尾的字串,但它會當做緩衝區來保存多個檔案名。 每個檔案名都必須以一般單 一 Null 字元終止。 額外的 Null 字元必須附加至最終名稱的結尾,以指出 pFrom的結尾。
pTo成員是雙null終止的字串,非常類似pFrom。 pTo成員包含一或多個完整目的地名稱的名稱。 它們會以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 會將連結新增至適當的檔系統資料夾,以及更新其最近檔和 [開始] 功能表的清單。 您也可以使用此函式來清除資料夾。