我正在寻找一种有效的方法,将绝对文件路径转换为相对于特定目录的路径。
假设我们必须遵循以下结构:
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)绝对路径(文件的完整路径):
- 当路径部分相等时:跳过它们
-
当我们遇到差异时
- 为参考路径的每个剩余部分添加一个".."
- 从绝对路径添加剩余零件
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所解释的,您需要识别这两个路径中的公共部分,并将连接到目标规范路径末尾的..
的数量相加。