草庐IT

windows - 当两个路径可能是相对路径时,将路径与 Windows API 组合

coder 2024-06-06 原文

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

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 上运行。我查看了 shell path handling functions在 Windows API 中,但它们似乎不合适:

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

    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 路径:

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

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

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

最佳答案

#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 - 当两个路径可能是相对路径时,将路径与 Windows API 组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33150102/

有关windows - 当两个路径可能是相对路径时,将路径与 Windows API 组合的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  3. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  4. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  5. ruby - 这两个 Ruby 类初始化定义有什么区别? - 2

    我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是

  6. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

    之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

  7. ruby-on-rails - Rails - 使用/自定义 URL : '/dashboard' 指定根路径 - 2

    如何使此根路径转到:“/dashboard”而不仅仅是http://example.com?root:to=>'dashboard#index',:constraints=>lambda{|req|!req.session[:user_id].blank?} 最佳答案 您可以通过以下方式实现:root:to=>redirect('/dashboard')match'/dashboard',:to=>"dashboard#index",:constraints=>lambda{|req|!req.session[:user_id].b

  8. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  9. ruby - 具有两个参数的 block - 2

    我从用户Hirolau那里找到了这段代码:defsum_to_n?(a,n)a.combination(2).find{|x,y|x+y==n}enda=[1,2,3,4,5]sum_to_n?(a,9)#=>[4,5]sum_to_n?(a,11)#=>nil我如何知道何时可以将两个参数发送到预定义方法(如find)?我不清楚,因为有时它不起作用。这是重新定义的东西吗? 最佳答案 如果您查看Enumerable#find的文档,您会发现它只接受一个block参数。您可以将它发送两次的原因是因为Ruby可以方便地让您根据它的“并行赋

  10. ruby - 如何根据长度将路径数组转换为嵌套数组或散列 - 2

    我需要根据字符串路径的长度将字符串路径数组转换为符号、哈希和数组的数组给定以下数组:array=["info","services","about/company","about/history/part1","about/history/part2"]我想生成以下输出,对不同级别进行分组,根据级别的结构混合使用符号和对象。产生以下输出:[:info,:services,about:[:company,history:[:part1,:part2]]]#altsyntax[:info,:services,{:about=>[:company,{:history=>[:part1,:pa

随机推荐