如何在C中检索相对于给定目录的文件路径



我正在寻找一种有效的方法,将绝对文件路径转换为相对于特定目录的路径。

假设我们必须遵循以下结构:

D:maintest1blah.txt  
D:test2foo.txt

如果"D:main"是参考目录,那么结果将是:

  • blah.txt=>"\test1\blah.txt"
  • foo.txt=>"..\test2\foo.txt"

有线索吗?


记录说明:

看起来:

  • 没有统一的API函数(跨平台)来执行此操作
  • 对于其他语言,这个问题已经被问过很多次了(尽管大多数答案都利用了函数PathRelativePathTo):

    • 如何从绝对路径中获取相对路径
    • 获取相对于特定目录的文件路径
    • 如何在C中获得从一条路径到另一条路径的相对路径#

您在示例中给出了windows路径。因此,如果您可以接受使用WinAPI函数,则可以使用PathRelativePathTo。

这是我能找到的最短解决方案。

算法其实很简单:

给定1)参考路径(结果路径将与之相关的路径);和2)绝对路径(文件的完整路径):

  • 当路径部分相等时:跳过它们
  • 当我们遇到差异时

    1. 为参考路径的每个剩余部分添加一个".."
    2. 从绝对路径添加剩余零件

windows下唯一的限制是在不同卷(驱动器号不同)的情况下,在这种情况下,我们别无选择,只能返回原始的绝对路径。

跨平台C来源:

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
    const char* path_separator = "\";
#else
    const char* path_separator = "/";
#endif  
#define FILENAME_MAX 1024

char* get_relative_path(char* reference_path, char* absolute_path) {
    static char relative_path[FILENAME_MAX];
    // init result string
    relative_path[0] = '';    
    // check first char (under windows, if differs, we return absolute path)
    if(absolute_path[0] != reference_path[0]) {
        return absolute_path;
    }    
    // make copies to prevent altering original strings
    char* path_a = strdup(absolute_path);
    char* path_r = strdup(reference_path);
    int inc;
    int size_a = strlen(path_a)+1;
    int size_r = strlen(path_r)+1;
    for(inc = 0; inc < size_a && inc < size_r; inc += strlen(path_a+inc)+1) {
        char* token_a = strchr(path_a+inc, path_separator[0]);
        char* token_r = strchr(path_r+inc, path_separator[0]);        
        if(token_a) token_a[0] = '';
        if(token_r) token_r[0] = '';        
        if(strcmp(path_a+inc, path_r+inc) != 0) break;
    }
    for(int inc_r = inc; inc_r < size_r; inc_r += strlen(path_r+inc_r)+1) {
        strcat(relative_path, "..");
        strcat(relative_path, path_separator);        
        if( !strchr(reference_path+inc_r, path_separator[0]) ) break;
    }
    if(inc < size_a) strcat(relative_path, absolute_path+inc);
    return relative_path;
}

首先需要确定文件路径分隔符,如下所述。

const char kPathSeparator =
#ifdef _WIN32
                            '\';
#else
                            '/';
#endif

然后,您需要编写一个函数来计算规范的绝对文件路径。您将不得不再次使用#ifdef _WIN32,因为需要特定的窗口处理(如果不存在,则在路径的开头添加当前磁盘)。之后,删除路径中的所有.,并删除所有..及其上一个目录。

一旦编写了这个函数,您需要使用它两次来获得原点和目标规范绝对路径,然后如@Weather Vane所解释的,您需要识别这两个路径中的公共部分,并将连接到目标规范路径末尾的..的数量相加。

最新更新