如何建立相对于特定文件夹的绝对路径?

时间:2012-01-28 04:16:32

标签: c# .net path

例如,我该如何制作

"C:\RootFolder\SubFolder\MoreSubFolder\LastFolder\SomeFile.txt"

相对于此文件夹

"C:\RootFolder\SubFolder\"

如果预期结果是

"MoreSubFolder\LastFolder\SomeFile.txt"

4 个答案:

答案 0 :(得分:35)

是的,您可以这样做,很容易,将您的路径视为URI

Uri fullPath = new Uri(@"C:\RootFolder\SubFolder\MoreSubFolder\LastFolder\SomeFile.txt", UriKind.Absolute);
Uri relRoot = new Uri(@"C:\RootFolder\SubFolder\", UriKind.Absolute);

string relPath = relRoot.MakeRelativeUri(fullPath).ToString();
// relPath == @"MoreSubFolder\LastFolder\SomeFile.txt"

答案 1 :(得分:15)

在您的示例中,它只是absPath.Substring(relativeTo.Length)

更详细的示例需要从relativeTo返回几个级别,如下所示:

"C:\RootFolder\SubFolder\MoreSubFolder\LastFolder\SomeFile.txt"
"C:\RootFolder\SubFolder\Sibling\Child\"

制作相对路径的算法如下所示:

  • 删除最长的公共前缀(在本例中为"C:\RootFolder\SubFolder\"
  • 计算relativeTo中的文件夹数量(在这种情况下,它是2:"Sibling\Child\"
  • 为每个剩余文件夹插入..\
  • 与后缀删除后的其余绝对路径连接

最终结果如下:

"..\..\MoreSubFolder\LastFolder\SomeFile.txt"

答案 2 :(得分:1)

这是我的5美分,没有为此目的使用任何特殊的Url类。

在以下git存储库中搜索makeRelativehttps://github.com/tapika/syncProj/blob/8ea41ebc11f538a22ed7cfaf59a8b7e0b4c3da37/syncProj.cs#L1685

(固定版一次冻结,分别搜索最新版本)

如果有错误,我会修复错误。

以下是上述链接中相同代码的副本:

/// <summary>
/// Rebases file with path fromPath to folder with baseDir.
/// </summary>
/// <param name="_fromPath">Full file path (absolute)</param>
/// <param name="_baseDir">Full base directory path (absolute)</param>
/// <returns>Relative path to file in respect of baseDir</returns>
static public String makeRelative(String _fromPath, String _baseDir)
{
    String pathSep = "\\";
    String fromPath = Path.GetFullPath(_fromPath);
    String baseDir = Path.GetFullPath(_baseDir);            // If folder contains upper folder references, they gets lost here. "c:\test\..\test2" => "c:\test2"

    String[] p1 = Regex.Split(fromPath, "[\\\\/]").Where(x => x.Length != 0).ToArray();
    String[] p2 = Regex.Split(baseDir, "[\\\\/]").Where(x => x.Length != 0).ToArray();
    int i = 0;

    for (; i < p1.Length && i < p2.Length; i++)
        if (String.Compare(p1[i], p2[i], true) != 0)    // Case insensitive match
            break;

    if (i == 0)     // Cannot make relative path, for example if resides on different drive
        return fromPath;

    String r = String.Join(pathSep, Enumerable.Repeat("..", p2.Length - i).Concat(p1.Skip(i).Take(p1.Length - i)));
    return r;
}

答案 3 :(得分:-2)

为什么所有这些复杂的解决方案? 并涉及到Uri?真的吗?您不必等待第一个例外 简洁明了。
不需要任何额外的框架类。

    public static string BuildRelativePath(string absolutePath, string basePath)
    {
        return absolutePath.Substring(basePath.Length);
    }

以防你无法总是添加或总是忽略关闭System.IO.Path.DirectorySeparatorChar到你的字符串,或者你不能混淆参数:

public static string FaultTolerantRelativePath(string absolutePath, string basePath)
{
    if(absolutePath == null || basePath == null)
        return null;

    absolutePath = absolutePath.Replace(System.IO.Path.DirectorySeparatorChar, '/');
    basePath = basePath.Replace(System.IO.Path.DirectorySeparatorChar, '/');

    if (!basePath.EndsWith("/"))
        basePath += "/";

    if (!absolutePath.EndsWith("/"))
        absolutePath += "/";

    if (absolutePath.Length < basePath.Length)
        throw new ArgumentException("absolutePath.Length < basePath.Length ? This can't be. You mixed up absolute and base path.");

    string resultingPath = absolutePath.Substring(basePath.Length);
    resultingPath = resultingPath.Replace('/', System.IO.Path.DirectorySeparatorChar);

    return resultingPath;
}