java-如何检查给定路径是否可能是其他路径的子代?

我试图找到给定的路径是否可能是使用java的另一个路径的子级。 这两个路径可能不存在。

假设c:\Program Files\My Company\test\My Appc:\Program Files的可能子级。

目前,我正在与

boolean myCheck(File maybeChild, File possibleParent)
{
    return maybeChild.getAbsolutePath().startsWith( possibleParent.getAbsolutePath());
}
Jayan asked 2020-08-11T07:26:24Z
9个解决方案
58 votes

您还可以使用java.nio.file.Path轻松完成此操作。 java.nio.file.Path.startsWith方法似乎可以处理所有可能的情况。

例:

private static void isChild(Path child, String parentText) {
    Path parent = Paths.get(parentText).toAbsolutePath();
    System.out.println(parentText + " = " + child.startsWith(parent));
}

public static void main(String[] args) {
    Path child = Paths.get("/FolderA/FolderB/File").toAbsolutePath();
    isChild(child, "/FolderA/FolderB/File");
    isChild(child, "/FolderA/FolderB/F");
    isChild(child, "/FolderA/FolderB");
    isChild(child, "/FolderA/Folder");
    isChild(child, "/FolderA");
    isChild(child, "/Folder");
    isChild(child, "/");
    isChild(child, "");
}

输出

/FolderA/FolderB/File = true
/FolderA/FolderB/F = false
/FolderA/FolderB = true
/FolderA/Folder = false
/FolderA = true
/Folder = false
/ = true
 = false

如果需要更高的可靠性,可以使用“ toRealPath”代替“ toAbsolutePath”。

Jecho Jekov answered 2020-08-11T07:26:43Z
12 votes
File parent = maybeChild.getParentFile();
while ( parent != null ) {
  if ( parent.equals( possibleParent ) )
    return true;
  parent = parent.getParentFile();
}
return false;
biziclop answered 2020-08-11T07:26:58Z
11 votes

从路径可能不存在(并且规范化可能不会成功)这一事实来看,这似乎是一种应该在简单情况下起作用的合理方法。

您可能想看看在一个循环中的“也许是孩子”上调用getParentFile(),以在每个步骤中测试它是否与父对象匹配。 如果父级不是(真实)目录,您还可以缩短比较的时间。

也许像下面这样:

boolean myCheck(File maybeChild, File possibleParent) throws IOException
{
    final File parent = possibleParent.getCanonicalFile();
    if (!parent.exists() || !parent.isDirectory()) {
        // this cannot possibly be the parent
        return false;
    }

    File child = maybeChild.getCanonicalFile();
    while (child != null) {
        if (child.equals(parent)) {
            return true;
        }
        child = child.getParentFile();
    }
    // No match found, and we've hit the root directory
    return false;
}

请注意,如果您希望子关系严格(即目录不是其自身的子目录),则可以将第9行的初始child分配更改为child.getParentFile(),以便在该子目录的包含目录上进行第一次检查。

Andrzej Doyle answered 2020-08-11T07:27:34Z
7 votes

这将为您的示例工作。 如果孩子是相对路径,它也会返回true(通常是理想的。)

boolean myCheck(File maybeChild, File possibleParent)
{
    URI parentURI = possibleParent.toURI();
    URI childURI = maybeChild.toURI();
    return !parentURI.relativize(childURI).isAbsolute();
}
finnw answered 2020-08-11T07:27:54Z
4 votes

尽管我将使用3006362862345520122012而不是30063628623455201220129,但这可能会很好地工作。这应该将任何奇怪的路径(如x/../y/z)标准化,否则会破坏匹配。

skaffman answered 2020-08-11T07:28:15Z
3 votes
maybeChild.getCanonicalPath().startsWith( possibleParent.getCanonicalPath() );
user1988293 answered 2020-08-11T07:28:31Z
1 votes

注意相对路径! 我认为最简单的解决方案是这样的:

public boolean myCheck(File maybeChild, File possibleParent) {
  if (requestedFile.isAbsolute) {
    return possibleParent.resolve(maybeChild).normalize().toAbsolutePath.startsWith(possibleParent.normalize().toAbsolutePath)
  } else {
    return maybeChild.normalize().toAbsolutePath.startsWith(possibleParent.normalize().toAbsolutePath)
  }
}

在scala中,您可以使用类似的方法:

val baseDir = Paths.get("/home/luvar/tmp")
val baseDirF = baseDir.toFile
//val requestedFile = Paths.get("file1")
val requestedFile = Paths.get("../.viminfo")
val fileToBeRead = if (requestedFile.isAbsolute) {
  requestedFile
} else {
  baseDir.resolve(requestedFile)
}
fileToBeRead.toAbsolutePath
baseDir.toAbsolutePath
fileToBeRead.normalize()
baseDir.normalize()
val isSubpath = fileToBeRead.normalize().toAbsolutePath.startsWith(baseDir.normalize().toAbsolutePath)
Ľubomír Varga answered 2020-08-11T07:28:56Z
0 votes

老问题,但1.7之前的解决方案:

public boolean startsWith(String possibleRoot, String possibleChildOrSame) {
        String[] possiblePath = new File(possibleRoot).getAbsolutePath().replace('\\', '/').split("/");
        String[] possibleChildOrSamePath = new File(possibleChildOrSame).getAbsolutePath().replace('\\', '/').split("/");

        if (possibleChildOrSamePath.length < possiblePath.length) {
            return false;
        }

        // not ignoring case
        for (int i = 0; i < possiblePath.length; i++) {
            if (!possiblePath[i].equals(possibleChildOrSamePath[i])) {
                return false;
            }
        }
        return true;
}

为了完整起见,Java 1.7+解决方案:

public boolean startsWith(String possibleRoot, String possibleChildOrSame) {
        Path p1 = Paths.get(possibleChildOrSame).toAbsolutePath();
        Path p2 = Paths.get(possibleRoot).toAbsolutePath();
        return p1.startsWith(p2);
}
Mattias Isegran Bergander answered 2020-08-11T07:29:21Z
0 votes

令人惊讶的是,没有简单但实用的解决方案。

接受的答案确实认为与子目录相同,这是错误的。

这是仅使用java.nio.file.Path API的一种:

static boolean isChildPath(Path parent, Path child){
      Path pn = parent.normalize();
      Path cn = child.normalize();
      return cn.getNameCount() > pn.getNameCount() && cn.startsWith(pn);
}

测试用例:

 @Test
public void testChildPath() {
      assertThat(isChildPath(Paths.get("/FolderA/FolderB/F"), Paths.get("/FolderA/FolderB/F"))).isFalse();
      assertThat(isChildPath(Paths.get("/FolderA/FolderB/F"), Paths.get("/FolderA/FolderB/F/A"))).isTrue();
      assertThat(isChildPath(Paths.get("/FolderA/FolderB/F"), Paths.get("/FolderA/FolderB/F/A.txt"))).isTrue();

      assertThat(isChildPath(Paths.get("/FolderA/FolderB/F"), Paths.get("/FolderA/FolderB/F/../A"))).isFalse();
      assertThat(isChildPath(Paths.get("/FolderA/FolderB/F"), Paths.get("/FolderA/FolderB/FA"))).isFalse();

      assertThat(isChildPath(Paths.get("FolderA"), Paths.get("FolderA"))).isFalse();
      assertThat(isChildPath(Paths.get("FolderA"), Paths.get("FolderA/B"))).isTrue();
      assertThat(isChildPath(Paths.get("FolderA"), Paths.get("FolderA/B"))).isTrue();
      assertThat(isChildPath(Paths.get("FolderA"), Paths.get("FolderAB"))).isFalse();
      assertThat(isChildPath(Paths.get("/FolderA/FolderB/F"), Paths.get("/FolderA/FolderB/F/Z/X/../A"))).isTrue();
}
Arthur H. answered 2020-08-11T07:29:54Z
translate from https://stackoverflow.com:/questions/4746671/how-to-check-if-a-given-path-is-possible-child-of-another-path