【发布时间】:2011-12-26 20:52:16
【问题描述】:
如何检查一条路径是否是另一条路径的子路径?
仅检查子字符串不是一种方法,因为可以有诸如 .和..等
【问题讨论】:
如何检查一条路径是否是另一条路径的子路径?
仅检查子字符串不是一种方法,因为可以有诸如 .和..等
【问题讨论】:
不幸的是它不像StartsWith那么简单。
这是一个更好的答案,改编自this重复问题。为了便于使用,我将其作为扩展方法。此外,使用蛮力catch 几乎任何访问文件系统的方法都可能因用户权限而失败。
public static bool IsSubDirectoryOf(this string candidate, string other)
{
var isChild = false;
try
{
var candidateInfo = new DirectoryInfo(candidate);
var otherInfo = new DirectoryInfo(other);
while (candidateInfo.Parent != null)
{
if (candidateInfo.Parent.FullName == otherInfo.FullName)
{
isChild = true;
break;
}
else candidateInfo = candidateInfo.Parent;
}
}
catch (Exception error)
{
var message = String.Format("Unable to check directories {0} and {1}: {2}", candidate, other, error);
Trace.WriteLine(message);
}
return isChild;
}
【讨论】:
IsSubDirectoryOf(@"c:\a\b", @"c:\A") 返回错误
.StartsWith 不起作用,而是它只是说明并解释了更复杂的解决方案 (-1)
任何基于字符串的解决方案都可能受到directory traversal attacks 或尾部斜杠等正确性问题的影响。不幸的是,.NET Path 类不提供此功能,但 Uri 类以Uri.IsBaseOf() 的形式提供。
Uri potentialBase = new Uri(@"c:\dir1\");
Uri regular = new Uri(@"c:\dir1\dir2");
Uri confusing = new Uri(@"c:\temp\..\dir1\dir2");
Uri malicious = new Uri(@"c:\dir1\..\windows\system32\");
Console.WriteLine(potentialBase.IsBaseOf(regular)); // True
Console.WriteLine(potentialBase.IsBaseOf(confusing)); // True
Console.WriteLine(potentialBase.IsBaseOf(malicious)); // False
【讨论】:
IsBaseOf 似乎不适用于此。给定输入 'C:\somerandomdir' 和 'C:\someotherdir',我得到了一个真实的结果。
IsBaseOf 甚至做出如此奇怪的猜测,比如砍掉它认为是文件名的东西,而这显然不是来电者提出的问题?如果有这样的警告和奇怪的细节需要担心,你的答案至少应该解决它们。
我用过这样的扩展方法:
/// <summary>
/// Check if a directory is the base of another
/// </summary>
/// <param name="root">Candidate root</param>
/// <param name="child">Child folder</param>
public static bool IsBaseOf(this DirectoryInfo root, DirectoryInfo child)
{
var directoryPath = EndsWithSeparator(new Uri(child.FullName).AbsolutePath);
var rootPath = EndsWithSeparator(new Uri(root.FullName).AbsolutePath);
return directoryPath.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase);
}
private static string EndsWithSeparator(string absolutePath)
{
return absolutePath?.TrimEnd('/','\\') + "/";
}
【讨论】:
这是我的解决方案:
// length parentDirectory <= length subDirectory
static private bool isParentDirectory(string parentDirectory, string subDirectory)
{
if (!subDirectory.Contains(parentDirectory)) return false;
string[] folders1 = subDirectory.Split('\\');
string[] folders2 = parentDirectory.Split('\\');
for (int i = 0; i < folders2.Count(); i++)
{
if (folders2[i] != folders1[i])
return false;
}
return true;
}
【讨论】:
`, when it could be .Net Core running on linux where the file separator is /. It also seems pointless to split, then compare each segment. Isn't that the same as a StartsWith`?
在 C# 中你可以这样做:
string cp = Path.GetFullPath(childPath);
string pp = Path.GetFullPath(parentPath);
if(pp.StartsWith(cp))
return true;
else
return false;
【讨论】:
我发现这适用于 windows:
if (pathA.Equals(pathB, StringComparison.OrdinalIgnoreCase) ||
pathA.StartsWith(pathB + "\\", StringComparison.OrdinalIgnoreCase))
如果你的路径可能有尾随字符,你可以先这样规范化它们:
pathA = Path.GetFullPath(pathA);
pathB = Path.GetFullPath(pathB);
【讨论】:
有同样的问题。如果路径为字符串,则可以使用StartWith()
if (pathA.StartsWith (pathB + "\\")) {
虽然我不确定它是否是跨平台的,但它确实可以在 PC 上运行
【讨论】:
这是一种方法,你有路径 A 和 B,使用 Path.GetFullPath() 函数将它们转换为完整路径。接下来检查一个完整路径是否是另一个的起始子字符串。
原来如此
if (Path.GetFullPath(A).StartsWith(Path.GetFullPath(B)) ||
Path.GetFullPath(B).StartsWith(Path.GetFullPath(A)))
{ /* ... do your magic ... */ }
【讨论】:
A 是C:\my\dir 并且B 是C:\my\dir2,这是否正常工作?那应该是false,但我认为Path.GetFullPath(B).StartsWith(Path.GetFullPath(A)) 应该是true。
.StartsWith 似乎是此处发布的其他答案的一个体面、更简单的替代方案。更重要的是,其他答案没有提供任何充分的理由说明 .StartsWith 不起作用。 @Charlie 投票第二高的答案没有说明为什么 .StartsWith 不起作用,它只是声明了它。
$"{input.TrimEnd(Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar)}" 即可解决斜杠问题。我理解您为什么认为 DirectoryInfo 是这样做的“正确”方式,但它要慢得多并且通常是不必要的。此外,.StartsWith 似乎是直观的解决方案,我认为这个答案不值得负分。