是否有可靠的方法来计算Path.Combine()的反转?
Path.Combine(“c:\ folder”,“subirectory \ something.txt”)可能会返回类似“c:\ folder \ subdirectory \ something.text”的内容。我想要的是inverse,一个函数,其中Path.GetRelativeUrl(“c:\ folder”,“c:\ folder \ subdirectory \ something.text”)将返回类似“”subdirectory \ something.txt“的内容。
一种解决方案是进行字符串比较并修剪根,但当相同的路径以不同的方式表达时(在路径表达式中使用“..”或“~1”),这不起作用。
答案 0 :(得分:20)
好吧,在我的情况下,我没有一些更难处理的边缘情况(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);
}
}
它看起来效果很好。至少,它通过了这些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");
}
}
测试用例依赖于现有的某些文件..这些文件在大多数Windows安装中很常见,但您的里程可能会有所不同。
答案 1 :(得分: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);
哪个给出了
../something.text
现在,路径的8.3名称(短名称)是另一回事。我的理解是这些路径存储在文件系统中,你必须使用win32来获取它们。此外,他们可以被禁用,因此无法保证他们在那里。要从短路径获取长路径,请在Kernel32.dll中调用GetLongPathName。这也意味着文件必须存在。
如果你想这样做,那么这个网站就是你的朋友。 GetLongPathName
答案 2 :(得分:3)
我用以下功能完成了它。第一个参数是我们正在查找的目录,第二个参数是目标路径。两条路径都可以是相对的。该功能未经优化,但可以完成其工作。
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 :(得分:0)
首先尝试Path.GetFullPath,然后尝试字符串比较。