首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >计算相对于某个根的路径- Path.Combine的逆

计算相对于某个根的路径- Path.Combine的逆
EN

Stack Overflow用户
提问于 2009-10-28 03:11:50
回答 4查看 6.1K关注 0票数 22

有没有一种可靠的方法来计算Path.Combine()的逆?

Path.Combine("c:\folder","subdirectory\something.txt")可能会返回类似"c:\folder\subdirectory\something.text“的内容。我想要的是相反的,一个函数,其中Path.GetRelativeUrl("c:\folder","c:\folder\subdirectory\something.text")将返回类似于""subdirectory\something.txt“”的内容。

一种解决方案是进行字符串比较并修剪根,但当相同的路径以不同的方式表示时,这将不起作用(使用"..“或路径表达式中的"~1“)。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-10-28 08:36:13

好的,所以在我的例子中,我没有一些比较棘手的情况(fullPath和relativePath混合网络映射位置,超长文件名)。我最终做的是创建下面的类

代码语言:javascript
复制
public class PathUtil
{
    static public string NormalizeFilepath(string filepath)
    {
        string result = System.IO.Path.GetFullPath(filepath).ToLowerInvariant();

        result = result.TrimEnd(new [] { '\\' });

        return result;
    }

    public static string GetRelativePath(string rootPath, string fullPath)
    {
        rootPath = NormalizeFilepath(rootPath);
        fullPath = NormalizeFilepath(fullPath);

        if (!fullPath.StartsWith(rootPath))
            throw new Exception("Could not find rootPath in fullPath when calculating relative path.");

        return "." + fullPath.Substring(rootPath.Length);
    }
}

它似乎工作得很好。至少,它通过了这些NUnit测试:

代码语言:javascript
复制
[TestFixture]
public class PathUtilTest
{
    [Test]
    public void TestDifferencesInCapitolizationDontMatter()
    {
        string format1 = PathUtil.NormalizeFilepath("c:\\windows\\system32");
        string format2 = PathUtil.NormalizeFilepath("c:\\WindowS\\System32");

        Assert.AreEqual(format1, format2);
    }

    [Test]
    public void TestDifferencesDueToBackstepsDontMatter()
    {
        string format1 = PathUtil.NormalizeFilepath("c:\\windows\\system32");
        string format2 = PathUtil.NormalizeFilepath("c:\\Program Files\\..\\Windows\\System32");

        Assert.AreEqual(format1, format2);
    }

    [Test]
    public void TestDifferencesInFinalSlashDontMatter()
    {
        string format1 = PathUtil.NormalizeFilepath("c:\\windows\\system32");
        string format2 = PathUtil.NormalizeFilepath("c:\\windows\\system32\\");

        Console.WriteLine(format1);
        Console.WriteLine(format2);

        Assert.AreEqual(format1, format2);
    }

    [Test]
    public void TestCanCalculateRelativePath()
    {
        string rootPath = "c:\\windows";
        string fullPath = "c:\\windows\\system32\\wininet.dll";
        string expectedResult = ".\\system32\\wininet.dll";

        string result = PathUtil.GetRelativePath(rootPath, fullPath);

        Assert.AreEqual(expectedResult, result);
    }

    [Test]
    public void TestThrowsExceptionIfRootDoesntMatchFullPath()
    {
        string rootPath = "c:\\windows";
        string fullPath = "c:\\program files\\Internet Explorer\\iexplore.exe";

        try
        {
            PathUtil.GetRelativePath(rootPath, fullPath);
        }
        catch (Exception)
        {
            return;
        }

        Assert.Fail("Exception expected");
    }
}

测试用例依赖于现有的某些文件。这些文件在大多数Windows安装中都是常见的,但您的安装里程可能会有所不同。

票数 23
EN

Stack Overflow用户

发布于 2009-10-28 05:51:10

我试图找到一种方法来处理长文件路径,但我没有得到令人满意的结果,因为当您使用标准文件系统调用的长路径版本时,您会丢失Win32中的路径规范化。因此,这个解决方案不一定适用于超过260个字符的内容,但它是托管代码,除此之外,它的大脑非常简单。

代码语言:javascript
复制
string path1 = @"c:\folder\subdirectory\something.text";
string path2 = @"c:\folder\foo\..\something.text";
Uri value = new Uri(path1);
Uri value2 = new Uri(path2);
Uri result = value.MakeRelativeUri(value2);
Console.WriteLine(result.OriginalString);

这给了我们

代码语言:javascript
复制
../something.text

现在,路径的8.3名称(简称)是另一回事了。据我所知,这些路径存储在文件系统中,您必须使用win32来获取它们。此外,它们可以被禁用,因此不能保证它们在那里。要从短路径获取长路径,您可以在Kernel32.dll中调用GetLongPathName。这也意味着文件必须存在。

如果你想这样做,那么这个网站就是你的朋友。GetLongPathName

票数 5
EN

Stack Overflow用户

发布于 2009-11-12 23:20:48

我用下面的函数做到了这一点。第一个参数是我们正在查找的目录,第二个参数是目标路径。这两个路径都可以是相对路径。该函数并未优化,但却完成了它的工作。

代码语言:javascript
复制
private string _GetRelativePath(string fromPath, string toPath)
{
  string fromFull = Path.Combine(Environment.CurrentDirectory, fromPath);
  string toFull = Path.Combine(Environment.CurrentDirectory, toPath);

  List<string> fromParts = new List<string> 
        fromFull.Split(Path.DirectorySeparatorChar));
  List<string> toParts = 
        new List<string>(toFull.Split(Path.DirectorySeparatorChar));

  fromParts.RemoveAll(string.IsNullOrEmpty);
  toParts.RemoveAll(string.IsNullOrEmpty);

  // Remove all the same parts in front
  bool areRelative = false;
  while ( fromParts.Count > 0 && toParts.Count > 0 &&
        StringComparer.OrdinalIgnoreCase.Compare(fromParts[0], toParts[0]) == 0 )
  {
        fromParts.RemoveAt(0);
        toParts.RemoveAt(0);

        areRelative = true;
  }

  if ( !areRelative )
        return toPath;

  // Number of remaining fromParts is number of parent dirs
  StringBuilder ret = new StringBuilder();

  for ( int i = 0; i < fromParts.Count; i++ )
  {
        if ( ret.Length > 0 )
              ret.Append(Path.DirectorySeparatorChar);

        ret.Append("..");
  }

  // And the remainder of toParts
  foreach (string part in toParts)
  {
        if ( ret.Length > 0 )
              ret.Append(Path.DirectorySeparatorChar);

        ret.Append(part);
  }

  return ret.ToString();
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1633028

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档