1. 程式人生 > >Shell的檔案操作函式SHFileOperation

Shell的檔案操作函式SHFileOperation

功能:
1.複製一個或多個檔案
2.刪除一個或多個
3.重新命名檔案
4.移動一個或多個檔案

有一樣的Win32API功能函式是:
CopyFile(),DeleteFile(),MoveFile()
MoveFile可以對檔案重新命名!
Win32 API 的層次比SHFileOperation低

SHFileOperation
的重要引數
1.wFunc //對pFrom pTo要執行的操作
2.fFlags //影響對wFunx的操作
3.hNameMappings //有系統填充,和你也可以填充
4.lpszProgressTitle

pFrom pTo 在結尾是兩個'\0\0'
通常用一個'\0',這樣會失敗的!!
當FOF_MULTIDESTFILES
szPFrom[lstrlen(szPFrom)+1]=0

szPFrom:必須先確定他所指定的檔案存在!
可以是單個檔名,*.*,或包含統配符的檔名
注意必須是檔名,不是檔案所在的資料夾名
szSource:可以是一個目錄,如果不是目錄,但又有
多個檔案,那麼必須和szPFrom的每一個檔案對應,還要指定
FOF_MULTIDETFILES標誌


Source and Target
多個檔案---> 一個資料夾
許多單獨的檔案---->一個資料夾
單獨檔案--->單獨檔案
許多單獨的檔案---->許多單獨的檔案

單獨檔案:知道名字的檔案
多個檔案:帶有統配符的檔案
注意到source中沒有對資料夾的操作!!


!!!!
SHFileOperation能操作網路上的檔案
如果你想將本地檔案複製到192.168.1.99
那麼只要在192.168.1.99上共享123目錄
然後將pTo設定為

\\192.168.1.99\123
就可以了
但不要設定為
\\192.168.1.99


對hNameMappings操作是Undocumented!!
如果沒有指定hNameMappings
那麼hNameMappings一直是NULL
只有當某種操作(copy,move,rename)引起了檔名衝突了,hNameMappings才不是NULL!!!
當第一次copy某些檔案到空目錄中時hNameMappings一定是NULL
所以hNameMappings只是記憶體中的一塊地區用來讓Explorer.exe儲存被重新命名的檔案,以避免檔名衝突!
上面知道了如何才能使hNameMappings有效
現在如何使用hNameMappings,及其所指的結構大小?並取得這個記憶體塊的內容呢?
hNameMappings 是簡單LPVOID無法使用loop
要使用hNameMappings,必須定義一個結構體
struct HANDLETOMAPPINGS {
UINT uNumberOfMappings; // number of mappings in array
LPSHNAMEMAPPING lpSHNameMapping; // pointer to array of mappings
};
但是可以寫一個Enumerate function to enumerate lpSHNameMapping指向的記憶體塊,並且是讓Window自己呼叫我的,不是我主動呼叫,象Loop

相關聯接:
Q154123:File Name Mapping with Windows NT 4.0 Shell
Q133326:SHFILEOPSTRUCT pFrom and pTo Fields Incorrect
Q142066:PRB: SHGetNameMappingPtr() and SHGetNameMappingCount()
Manipulating Files with the SHFileOperation Function in Visual Basic 4.0

FOF_SILENT //不產生正在複製的對話方塊
FOF_NOCONFIRMMKDIR//如果目的目錄不存在,就預設建立
FOF_NOCONFIRMATION //不出現確認檔案替換對話方塊(Confirmation Dialog)(預設替換原來的文i件)
FOF_NOERRORUI//不出現錯誤對話方塊
最好不要同時使用FOF_NOERRORUI,FOF_NOCONFIRMMKDIR
因為FOF_NOCONFIRMMKDIR遮蔽了missing directory Error
但FOF_NOERROR又遮蔽了missing directory Error,那麼在同時使用FOF_NOERRORUI,FOF_NOCONFIRMMKDIR
時也阻止了新目錄安靜(沒有使用者確認要產生新目錄的對話方塊)的產生!!
那麼如何同時使用FOF_NOERRORUI,FOF_NOCONFIRMMKDIR?
就必須先確認pTo所指定的目錄存在即可
BOOL MakeSureDiretoryPathExists(LPCSTR DirPath);

使用它要包含imagehlp.h和imagehlp.lib
如何判斷同時存在FOF_NOERRORUI,FOF_NOCONFIRMMKDIR

=====

因此本人註釋:如果出現彈出"無法刪除 檔案無法:讀取原始檔或磁碟文.",

可:FOF_NOCONFIRMATION|FOF_NOCONFIRMMKDIR|FOF_NOERRORUI

=====
FOF_RENAMEONCOLLISION//有重複檔案時自動重新命名


能產生對話方塊的標誌:
FOF_SILENT //progress dialog
FOF_RENAMEONCOLLISION //replace dialog
FOF_NOCONFIRMATION //confirmation dialog
FOF_NOCONFIRMMKDIR //asks for your permission to create a new folder
FOF_NOERRORUI //error message


FOF_ALLOWUNDO //將檔案放入回收站,否則直接刪除,一般這個最好做預設

///////////////////////////////////////////////////

//刪除檔案或者資料夾
bool DeleteFile(char * lpszPath)
{
SHFILEOPSTRUCT FileOp={0};
FileOp.fFlags = FOF_ALLOWUNDO | //允許放回回收站
FOF_NOCONFIRMATION; //不出現確認對話方塊
FileOp.pFrom = lpszPath;
FileOp.pTo = NULL; //一定要是NULL
FileOp.wFunc = FO_DELETE; //刪除操作
return SHFileOperation(&FileOp) == 0;
}

//複製檔案或資料夾
bool CopyFile(char *pTo,char *pFrom)
{
SHFILEOPSTRUCT FileOp={0};
FileOp.fFlags = FOF_NOCONFIRMATION| //不出現確認對話方塊
FOF_NOCONFIRMMKDIR ; //需要時直接建立一個資料夾,不需使用者確定
FileOp.pFrom = pFrom;
FileOp.pTo = pTo;
FileOp.wFunc = FO_COPY;
return SHFileOperation(&FileOp) == 0;
}

//移動檔案或資料夾
bool MoveFile(char *pTo,char *pFrom)
{
SHFILEOPSTRUCT FileOp={0};
FileOp.fFlags = FOF_NOCONFIRMATION| //不出現確認對話方塊
FOF_NOCONFIRMMKDIR ; //需要時直接建立一個資料夾,不需使用者確定
FileOp.pFrom = pFrom;
FileOp.pTo = pTo;
FileOp.wFunc = FO_MOVE;
return SHFileOperation(&FileOp) == 0; 
}


//從命名檔案或資料夾
bool ReNameFile(char *pTo,char *pFrom)
{
SHFILEOPSTRUCT FileOp={0};
FileOp.fFlags = FOF_NOCONFIRMATION; //不出現確認對話方塊
FileOp.pFrom = pFrom;
FileOp.pTo = pTo;
FileOp.wFunc = FO_RENAME;
return SHFileOperation(&FileOp) == 0; 
}

應用舉例:
DeleteFile("d:\\PID\0\0"); //刪除一個資料夾
DeleteFile("d:\\PID.dsp\0d:\\PID.dsw\0\0"); //刪除多個檔案
CopyFile("d:\0\0","D:\\MyProjects\\臨時程式\0\0"); //把"臨時程式"資料夾放到d盤下面
CopyFile("d:\0\0","D:\\MyProjects\\臨時程式
\\PID.dsp\0D:\\MyProjects\\臨時程式\\PID.dsw\0"); //把PID.dsp和PID.dsw倆個檔案放到d盤下面
ReNameFile("d:\\NewName","d:\\PID\0\0"); \\把PID資料夾從命名為NewName
注意:,如果你想把"D:\\MyProjects\\臨時程式\0\0"的資料夾複製到D盤下,並從命名為NewName,應該這樣
CopyFile("d:\\NewName\0\0","D:\\MyProjects\\臨時程式
\\*.*\0\0"); //把"臨時程式"資料夾複製到d盤下並從命名為"NewName"

下面這個類方便你複製多個檔案或資料夾,僅作參考
//連線多個路徑的類
class JOINFILEPATH
{
private:
int pos;
char* MultipleFilePath;
public:
JOINFILEPATH()
{
pos=0;
MultipleFilePath=new char[MAX_PATH*10];
memset(MultipleFilePath,0,MAX_PATH*10);
}
~JOINFILEPATH() { delete []MultipleFilePath; }
void join(char *FilePath)
{
while(*FilePath!='\0')
MultipleFilePath[pos++]=*FilePath++;
pos++;
}
char * GetMultipleFilePath() {return MultipleFilePath;}
};

//應用舉例:
JOINFILEPATH FilePath;
FilePath.join("D:\\MyProjects\\臨時程式
\\PID\\PID.dsp");
FilePath.join("D:\\MyProjects\\臨時程式
\\PID\\PID.dsw");
CopyFile("d:\0\0",FilePath.GetMultipleFilePath());

1 pFrom和pTo最好以\0\0結尾(把存放路徑的字串初始化為0),不然有可能會出錯,中間的每一個路徑用\0隔開
2 pFrom所指向的檔案或資料夾(可以多個)會被複制或移動到pTo所指向的資料夾下面(假如資料夾不存在會詢問是否建立,當然你也可以選擇直接建立)

引數詳解:

Typedef struct _ShFILEOPSTRUCT
{
HWND hWnd; //訊息傳送的視窗控制代碼;
UINT wFunc; //操作型別
LPCSTR pFrom; //原始檔及路徑
LPCSTR pTo; //目標檔案及路徑
FILEOP_FLAGS fFlags; //操作與確認標誌
BOOL fAnyOperationsAborted; //操作選擇位
LPVOID hNameMappings; //檔案對映
LPCSTR lpszProgressTitle; //檔案操作進度視窗標題
}SHFILEOPSTRUCT, FAR * LPSHFILEOPSTRUCT;

  在這個結構中,hWnd是指向傳送訊息的視窗控制代碼,pFrom與pTo是進行檔案操作的原始檔名和目標檔名,它包含檔案的路徑,對應單個檔案的路徑字串,或對於多個檔案,必須以NULL作為字串的結尾或檔案路徑名之間的間隔,否則在程式執行的時候會發生錯誤。另外,pFrom和pTo都支援萬用字元*和?,這大大方便了開發人員的使用。例如,原始檔或目錄有兩個,則應是:char pFrom[]="d:\\Test1\0d:\\Text.txt\0",它表示對要D:盤Test目錄下的所有檔案和D:盤上的Text.txt檔案進行操作。字串中的"\"是C語言中的'\'的轉義符,'\0'則是NULL。wFunc 是結構中的一個非常重要的成員,它代表著函式將要進行的操作型別,它的取值為如下:

  FO_COPY: 拷貝檔案pFrom到pTo 的指定位置。

  FO_RENAME: 將pFrom的檔名更名為pTo的檔名。

  FO_MOVE: 將pFrom的檔案移動到pTo的地方。

  FO_DELETE: 刪除pFrom指定的檔案。

  使用該函式進行檔案拷貝、移動或刪除時,如果需要的時間很長,則程式會自動在進行的過程中出現一個無模式的對話方塊(Windows作業系統提供的檔案操作對話方塊),用來顯示執行的進度和執行的時間,以及正在拷貝、移動或刪除的檔名,此時結構中的成員lpszProgressTitle顯示此對話方塊的標題。fFlags是在進行檔案操作時的過程和狀態控制標識。它主要有如下一些標識,也可以是其組合:

  FOF_FILESONLY:執行萬用字元,只執行檔案;

  FOF_ALLOWUNDO:儲存UNDO資訊,以便在回收站中恢復檔案;

  FOF_NOCONFIRMATION:在出現目標檔案已存在的時候,如果不設定此項,則它會出現確認是否覆蓋的對話方塊,設定此項則自動確認,進行覆蓋,不出現對話方塊。

  FOF_NOERRORUI:設定此項後,當檔案處理過程中出現錯誤時,不出現錯誤提示,否則會進行錯誤提示。

  FOF_RENAMEONCOLLISION:當已存在檔名時,對其進行更換文提示。

  FOF_SILENT:不顯示進度對話方塊。

  FOF_WANTMAPPINGHANDLE:要求SHFileOperation()函式返回正處於操作狀態的實際檔案列表,檔案列表名柄儲存在hNameMappings成員中。

  SHFILEOPSTRUCT結構還包含一個SHNAMEMAPPING結構的陣列,此陣列儲存由SHELL計算的每個處於操作狀態的檔案的新舊路徑。

  在使用該函式刪除檔案時必須設定SHFILEOPSTRUCT結構中的神祕FOF_ALLOWUNDO標誌,這樣才能將待刪除的檔案拷到Recycle Bin,從而使使用者可以撤銷刪除操作。需要注意的是,如果pFrom設定為某個檔名,用FO_DELETE標誌刪除這個檔案並不會將它移到Recycle Bin,甚至設定FOF_ALLOWUNDO標誌也不行,在這裡你必須使用全路徑名,這樣SHFileOperation才會將刪除的檔案移到Recycle Bin。