当两个路径可能是相对的时,将路径与 Windows API 合并 [英] Combine paths with Windows API when both paths may be relative

查看:29
本文介绍了当两个路径可能是相对的时,将路径与 Windows API 合并的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要能够将两个不同的 Windows 路径(这两个路径都可能是相对的)合并到一个路径中(通过应用第二个作为第一个的扩展).文件系统上是否实际存在任一路径都无关紧要.示例:

I need to be able to combine two different Windows paths, both of which may be relative, into a single path (by applying the second as an extension of the first). It should not matter whether either path actually exists on the filesystem. Examples:

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

理想情况下,它还应该将驱动器相关的绝对"路径(即以单个反斜杠开头的路径)解析为给定驱动器上的适当路径:

Ideally, it should also resolve drive-relative "absolute" paths (i.e. paths beginning with a single backslash) to the appropriate path on the given drive:

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

最后,如果它通过返回绝对路径来处理第二条绝对路径的情况,那就太好了:

Finally, it would be nice if it handled the case of the second path being absolute, by returning that absolute path:

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

另一种说法是:

我想要一个将路径A"和路径B"作为参数的函数.输出 'C' 应该与我先用 A 调用 SetCurrentDirectory 然后用 B 然后调用 GetCurrentDirectory 一样(但是,如果路径不'不存在,并且它在任何时候都不应该改变当前工作目录,如果 A 和 B 都是相对路径,结果应该是一个相对路径;我并不特别关心结果路径是否包含 '..' 段).

I want a function that takes as arguments a path 'A' and a path 'B'. The output 'C' should be the same as if I called SetCurrentDirectory first with A and then with B and then called GetCurrentDirectory (however, it should not matter if the paths don't exist, and it should at no point change the current working directory, and the result should be a relative path if both A and B are relative paths; I do not particularly care if the result path contains '..' segments).

代码需要在 Windows 7 上运行.我查看了 shell 路径处理函数,但它们似乎不合适:

The code needs to work on Windows 7. I've looked at the shell path handling functions in the Windows API, but they don't seem suitable:

  • 对于 PathAppend,第一个路径不能是相对的:

  • for PathAppend, the first path cannot be relative:

pszPath 中提供的路径不能以..\"或.\"开头产生一个相对路径字符串.如果存在,这些期间将被剥离来自输出字符串.

The path supplied in pszPath cannot begin with "..\" or ".\" to produce a relative path string. If present, those periods are stripped from the output string.

  • 对于 PathCombine,第一条路径不能是相对路径,不能是UNC路径:

  • for PathCombine, the first path cannot be relative and cannot be a UNC path:

    目录路径的格式应该是A:,B:,...,Z:

    The directory path should be in the form of A:,B:, ..., Z:

  • (编辑:仔细检查后,该文档片段似乎确实属于另一个函数.提到的参数名称与方法签名中给出的参数名称不同.在事实上,如下面的第二个答案所示,PathCombine 似乎确实适用于 UNC 路径.但是,它与 PathAppend 存在同样的问题 - 因为它去除了前导 ... 来自输出路径的段).

    (Edit: On closer inspection, that snippet of documentation seems like it might really belong to another function. The parameter names mentioned are not the same as the parameter names given in the method signature. In fact, as demonstrated in the second answer below, PathCombine does seem to work with UNC paths. However, it has the same problem that PathAppend does - in that it strips leading .. segments from the output path).

    • PathCchCombine and PathAllocCombine are only available on Windows 8 and beyond.

    是否有任何我忽略的标准函数,或者是否有任何库可以正确处理包括 UNC 样式路径在内的所有情况?或者至少有一种简单的方法可以使用其他已经可用的功能来实现满足我要求的功能?

    Are there any standard functions that I've overlooked, or is there any library which correctly handles all cases including UNC-style paths? Or is there at least a simple way to implement a function which meets my requirements using others that are already available?

    推荐答案

    #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'
    

    这篇关于当两个路径可能是相对的时,将路径与 Windows API 合并的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆