2015-10-15 26 views
2

我需要能夠將兩個不同的Windows路徑組合成一個路徑(通過將第二個路徑作爲第一個路徑的擴展名)。文件系統中是否存在任何路徑應該沒有關係。例子:當兩個路徑可能都是相對的時,將路徑與Windows API結合起來

C:\abc + def -> C:\abc\def 
C:\abc + ..\def -> C:\def 
\\server\share + def -> \\server\share\def 
..\some\path\abc + ..\def -> ..\some\path\def 
..\some\path + ..\..\..\def -> ..\..\def 

理想的情況下,還應該解決給定的驅動器上的驅動,相對的「絕對」路徑(即路徑開始與一個反斜槓)爲適當的路徑:

C:\abc + \def -> C:\def 

最後,將是很好,如果它處理的第二條路徑是絕對的情況下,通過返回絕對路徑:

C:\abc + D:\def -> D:\def 

把它的另一種方式是:

我想要一個函數,將路徑'A'和路徑'B'作爲參數。輸出'C'應該是相同的,如果我先用A調用SetCurrentDirectory然後用B調用然後調用GetCurrentDirectory(然而,如果路徑不存在並不重要,並且它不應該改變當前工作目錄,如果A和B都是相對路徑,結果應該是相對路徑;我不特別在意結果路徑是否包含'..'段)。

代碼需要在Windows 7上我已經看過了Windows API中的shell path handling functions工作,但他們似乎並不合適:

  • PathAppend,第一路徑不能是相對:

    pszPath中提供的路徑不能以「.. \」或「。\」開頭,因此產生相對路徑字符串爲 。如果存在,則從輸出字符串中除去 。

  • PathCombine,第一路徑不能是相對且不能UNC路徑:

    的目錄路徑應在A的形式:,B:,...,Z:

編輯:在仔細檢查,文件的片斷代碼看起來像它可能真正屬於另一個函數的參數名稱我。 ntioned與方法簽名中給出的參數名稱不同。事實上,如下面第二個答案所示,PathCombine似乎與UNC路徑一起工作。但是,它具有與PathAppend相同的問題 - 因爲它會從輸出路徑中刪除前導段..)。

是否有任何我忽略的標準功能,或者是否有任何庫能夠正確處理包括UNC風格路徑在內的所有情況?還是至少有一個簡單的方法來實現一個功能,使用其他已有的功能滿足我的要求?

+0

這聽起來像你可以使用'PathAppend'並編寫保存在第一路徑中的任何超前時段分支機構和事後恢復它們的包裝功能。 –

+0

@JonathanPotter這可能是一種可能性,是的。我仍然希望可能有一個更優雅的解決方案,但它看起來越來越不可能: – davmac

+0

'C:\ abc + \ def - > C:\ def'與C:\ abc + D:\不一致。 def - > D:\ def':在這兩種情況下,第二個路徑都是絕對路徑,但您希望以不同的方式處理它們。在第一個示例中,您可能會得到一條不存在的路徑('C:\ def') ,即使'\ def'也行。 – IInspectable

回答

0
#include <stdio.h> 
#include <stdlib.h> 

#ifndef MAX_PATH 
#define MAX_PATH 260 
#endif 

char *rootFolder(char *folder); 

int IsFullPath(const char *p){ 
    if(p && *p){ 
     if(((*p>='A') && (*p<='Z')) ||((*p>='a') && (*p<='z'))){ 
      return p[1]==':'; 
     } 
     return *p=='\\' & p[1]=='\\'; 
    } 
    return 0; 
} 
/*_______________________________________________________ 
*/ 
char *FolderUp(char *path,int deep){ 



    path=rootFolder(path); 
    if(!*path) return path; 

    int i=strlen(path); 

    char *p=path; 
    if(path[i-1]=='\\') path--; 

    while(i &&(deep>0)){ 
     i--; 
     if(path[i]=='\\'){ 
      p=&path[i+1]; 
      deep--; 
     } 
    } 
    return p; 

} 
/*_________________________________________________________________ 
*/ 
char *NextFolder(char *path){ 
    while(*path){ 
     path++; 
     if(*path=='\\'){ 
      path++; 
      break; 
     } 
    } 
    return path; 
} 
/*_________________________________________________________________ 
*/ 
char *rootFolder(char *folder){ 
    char *p; 
    if((*folder=='\\') && (folder[1]=='\\')){ 
     return NextFolder(&folder[2]); 
    } 

    if(*folder && folder[1]==':' && folder[2]=='\\') 
     return &folder[3]; 
    return folder; 
} 


int chdir(/*IN_OUT*/char *curDir,const /*IN*/char *newDir){ 

    int deep=0,i; 
    const char *p=newDir,*tmp; 


    if(!newDir ||!*newDir) return 0; 

    if(IsFullPath(newDir)){ 
     strcpy(curDir,newDir); 
     return 1; 
    } 

    if(*newDir=='\\'){ 
     tmp=rootFolder(curDir); 
     if(*tmp!='\\') tmp--; 
     strcpy(tmp,newDir); 
     return 1; 
    } 

    /**/ 

    while(*p && (p[0]=='.' && p[1]=='.')) { 
     if(p[2]!='\\') { 
      deep=0; 
      break; 
     } 
     p+=3; 
     deep++; 
    } 
    if(deep){ 
     tmp=FolderUp(curDir,deep); 
     if(tmp[-1]!='\\') p--; 
     strcpy(tmp,p); 
     return 1; 
    } 

    i=strlen(curDir); 
    if(i && curDir[i-1]!='\\'){ 
     curDir[i]='\\'; 
     curDir[i+1]=0; 
    } 
    strcat(curDir,newDir); 
    return 1; 
    /**/ 
} 

void DoTest(char *curDir,char *newDir){ 
    char path[MAX_PATH]; 
    strcpy(path,curDir); 

    if(chdir(path,newDir)) 
     printf("'%s' + '%s' -> %'%s'\n",curDir,newDir,path); 
    else 
     printf("Error: an unhandled error occured\n"); 
    return ; 

} 
int main(){ 

    DoTest("C:\\abc","def"); 
    DoTest("C:\\abc","..\\def"); 
    printf("\n"); 

    DoTest("C:\\abc\\","def"); 
    DoTest("C:\\abc\\","..\\def"); 
    printf("\n"); 

    DoTest("\\\\server\\share","def"); 
    DoTest("\\\\server\\share","..\\def"); 
    printf("\n"); 

    DoTest("\\\\server\\share\\","def"); 
    DoTest("\\\\server\\share\\","..\\def"); 
    printf("\n"); 

    DoTest("\\\\server","def"); 
    DoTest("\\\\server","..\\def"); 
    printf("\n"); 

    DoTest("\\\\server\\","def"); 
    DoTest("\\\\server\\","..\\def"); 
    printf("\n"); 

    DoTest("c:\\Folder","\\\\server\\share"); 
    DoTest("\\\\server\\share","c:\\Folder"); 
    printf("\n"); 

    DoTest("..\\Folder\\sub folder","..\\sibling"); 
    printf("\n"); 
    return 0; 
} 

這裏是輸出:

'C:\abc' + 'def' -> 'C:\abc\def' 
'C:\abc' + '..\def' -> 'C:\def' 

'C:\abc\' + 'def' -> 'C:\abc\def' 
'C:\abc\' + '..\def' -> 'C:\def' 

'\\server\share' + 'def' -> '\\server\share\def' 
'\\server\share' + '..\def' -> '\\server\def' 

'\\server\share\' + 'def' -> '\\server\share\def' 
'\\server\share\' + '..\def' -> '\\server\def' 

'\\server' + 'def' -> '\\server\def' 
'\\server' + '..\def' -> '\\server\def' 

'\\server\' + 'def' -> '\\server\def' 
'\\server\' + '..\def' -> '\\server\def' 

'c:\Folder' + '\\server\share' -> '\\server\share' 
'\\server\share' + 'c:\Folder' -> 'c:\Folder' 

'..\Folder\sub folder' + '..\sibling' -> '..\Folder\sibling' 
+1

兩種路徑都是相對的測試用例?這是問題的焦點。 –

+0

我爲兩條相對路徑添加了一個測試,並且它通過 – milevyo

+0

正確,這是有效的 - 雖然它仍然讓我覺得沒有預先存在的API函數來執行它。如果沒有更好的答案,我會在一兩天內接受。 – davmac

0

此使用WINAPI功能。

#include <stdio.h> 
#include <stdlib.h> 

#include <windows.h> 
#include <Shlwapi.h> 
//#pragma lib "Shlwapi.lib" 
#pragma comment(lib , "Shlwapi.lib" ) 



char *rootFolder(char *folder); 

int IsAbsolutePath(const char *p){ 
    return !PathIsRelative(p); 
} 
/*_______________________________________________________ 
*/ 

int chdir(/*IN_OUT*/char *curDir,const /*IN*/char *newDir){ 

    int deep=0,i; 
    char *p=(char*) newDir,*tmp; 


    if(!newDir ||!*newDir) return 0; 

    /*if(IsAbsolutePath(newDir)){ 
     strcpy(curDir,newDir); 
     return 1; 
    }*/ 
    return (int) PathCombine(curDir,curDir,newDir); 

    /**/ 
} 
/*_______________________________________________________ 
*/ 

void DoTest(char *curDir,char *newDir){ 
    char path[MAX_PATH]; 
    strcpy(path,curDir); 

    if(chdir(path,newDir)) 
     printf("'%s' + '%s' -> %'%s'\n",curDir,newDir,path); 
    else 
     printf("Error: an unhandled error occured\n"); 
    return ; 

} 
/*_______________________________________________________ 
*/ 

int main(){ 

    DoTest("C:\\abc","def"); 
    DoTest("C:\\abc","..\\def"); 
    printf("\n"); 

    DoTest("C:\\abc\\","def"); 
    DoTest("C:\\abc\\","..\\def"); 
    printf("\n"); 

    DoTest("\\\\server\\share","def"); 
    DoTest("\\\\server\\share","..\\def"); 
    printf("\n"); 

    DoTest("\\\\server\\share\\","def"); 
    DoTest("\\\\server\\share\\","..\\def"); 
    printf("\n"); 

    DoTest("\\\\server","def"); 
    DoTest("\\\\server","..\\def"); 
    printf("\n"); 

    DoTest("\\\\server\\","def"); 
    DoTest("\\\\server\\","..\\def"); 
    printf("\n"); 

    DoTest("c:\\Folder","\\\\server\\share"); 
    DoTest("\\\\server\\share","c:\\Folder"); 
    printf("\n"); 

    DoTest("c:\\Folder","\\share"); 
    DoTest("\\\\server\\share","\\Folder"); 
    printf("\n"); 

    DoTest("..\\Folder\\sub folder","..\\sibling"); 
    printf("\n"); 
    return 0; 
} 

這是輸出

'C:\abc' + 'def' -> 'C:\abc\def' 
'C:\abc' + '..\def' -> 'C:\def' 

'C:\abc\' + 'def' -> 'C:\abc\def' 
'C:\abc\' + '..\def' -> 'C:\def' 

'\\server\share' + 'def' -> '\\server\share\def' 
'\\server\share' + '..\def' -> '\\server\def' 

'\\server\share\' + 'def' -> '\\server\share\def' 
'\\server\share\' + '..\def' -> '\\server\def' 

'\\server' + 'def' -> '\\server\def' 
'\\server' + '..\def' -> '\\def' 

'\\server\' + 'def' -> '\\server\def' 
'\\server\' + '..\def' -> '\\def' 

'c:\Folder' + '\\server\share' -> '\\server\share' 
'\\server\share' + 'c:\Folder' -> 'c:\Folder' 

'c:\Folder' + '\share' -> 'c:\share' 
'\\server\share' + '\Folder' -> '\\server\share\Folder' 

'..\Folder\sub folder' + '..\sibling' -> 'Folder\sibling' 
+0

儘管看起來確實起作用,但您使用的是'PathCombine',它被記錄爲需要第二個參數的基於驅動器號的路徑。 – davmac

+0

另外這是一個不正確的結果:''.. \文件夾\子文件夾'+'.. \兄弟' - >'文件夾\兄弟' – davmac

+0

是的我知道,我只是演示了WINAPI如何處理這種情況。爲此我提供了以前的代碼(自制)。 – milevyo