如何检查一个路径是否是另一个路径的子路径?
仅仅检查子字符串并不可行,因为有可能会出现 . 和 .. 等项目。
很遗憾,这不像StartsWith
那样简单。
以下是一个更好的答案,改编自这个重复的问题。我将其作为扩展方法以方便使用。此外,我使用了暴力的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;
}
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
'C:\somerandomdir'
和 'C:\someotherdir'
,我得到了一个真结果。 - jpmc26IsBaseOf
会尝试截取它认为是文件名的内容,做出如此奇怪的猜测,而不是回答调用者所问的问题?如果有这样的警告和奇怪的细节需要担心,你的回答至少应该涉及到它们。 - jpmc26System.IO.Path.GetFullPath
?您暗示它不能使用。我很好奇为什么。 - GoWiser我曾经使用过这样的扩展方法:
最初的回答
/// <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('/','\\') + "/";
}
System.IO.Path.GetFullPath
? - GoWiser// 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;
}
\
,但在运行于Linux的.Net Core上,文件分隔符可能是/
。而且似乎将其拆分,然后比较每个段是毫无意义的。这不就相当于StartsWith
吗? - ErikEIsSubPath
函数会在child
是parent
的子目录时返回true。
public static bool IsSubPath(string parent, string child)
{
try
{
parent = Path.GetFullPath(parent);
if (!parent.EndsWith(Path.DirectorySeparatorChar.ToString()))
parent = parent + Path.DirectorySeparatorChar;
child = Path.GetFullPath(child);
if (child.Length <= parent.Length)
return false;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return child.StartsWith(parent, StringComparison.OrdinalIgnoreCase);
else
return child.StartsWith(parent);
}
catch
{
return false;
}
}
我发现这适用于Windows:
if (pathA.Equals(pathB, StringComparison.OrdinalIgnoreCase) ||
pathA.StartsWith(pathB + "\\", StringComparison.OrdinalIgnoreCase))
pathA = Path.GetFullPath(pathA);
pathB = Path.GetFullPath(pathB);
string cp = Path.GetFullPath(childPath);
string pp = Path.GetFullPath(parentPath);
if(pp.StartsWith(cp))
return true;
else
return false;
GetFullPath
函数返回值是否与原路径大小写相同,结果发现并不相同。还有一个问题是如何比较父目录 C:\asd1
和子目录 C:\asd11
。 - GoWiser我曾经遇到过同样的问题。如果你有路径字符串,可以使用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
。 - jpmc26.StartsWith
似乎是其他回答中不错、更简单的替代方案。更重要的是,其他回答没有提供任何确切的理由说明为什么 .StartsWith
不起作用。@Charlie 给出的第二高票答案没有解释为什么 .StartsWith
不起作用,只是宣称了一下。 - Hele$"{input.TrimEnd(Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar)}"
。我理解为什么你觉得DirectoryInfo是正确的方法,但它会更慢,而且通常是不必要的。此外,.StartsWith
似乎是直观的解决方案,我不认为这个答案应该得到负分。 - Hele
IsSubDirectoryOf(@"c:\a\b", @"c:\A")
返回 false。 - Gerd K