计算相对于某个根的路径 - Path.Combine的反转

Fra*_*man 21 .net path

有没有可靠的方法来计算Path.Combine()的倒数?

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

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

Fra*_*man 22

好吧,在我的情况下,我没有一些更强硬的边缘情况(fullPath和relativePath混合网络地图位置,超长文件名).我最终做的是创建下面的课程

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

[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");
    }
}
Run Code Online (Sandbox Code Playgroud)

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


Dan*_*air 5

我尝试使用长文件路径找到一种方法,但我只是没有得到满意的结果,因为当你使用标准文件系统调用的长路径版本时,你在Win32中失去了路径的规范化.因此,这个解决方案不一定适用于超过260个字符的事物,但它的托管代码和脑死亡简单.

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);
Run Code Online (Sandbox Code Playgroud)

这使

../something.text
Run Code Online (Sandbox Code Playgroud)

现在路径的8.3名称(短名称)是另一回事.我的理解是这些路径存储在文件系统中,你必须使用win32来获取它们.此外,他们可以被禁用,因此无法保证他们在那里.要从短路径获取长路径,请在Kernel32.dll中调用GetLongPathName.这也意味着文件必须存在.

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