it-swarm.com.ru

Как проверить, является ли данный путь возможным потомком другого пути?

Я пытаюсь найти, если данный путь является дочерним по отношению к другому пути с использованием Java. Оба пути могут не существовать.

Скажем, c:\Program Files\My Company\test\My App является возможным потомком c:\Program Files.

В настоящее время я делаю это с 

boolean myCheck(File maybeChild, File possibleParent)
{
    return maybeChild.getAbsolutePath().startsWith( possibleParent.getAbsolutePath());
}
34
Jayan

Вы также можете использовать 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».

48
Jecho Jekov
File parent = maybeChild.getParentFile();
while ( parent != null ) {
  if ( parent.equals( possibleParent ) )
    return true;
  parent = parent.getParentFile();
}
return false;
11
biziclop

Помимо того, что пути могут не существовать (и канонизация может не увенчаться успехом), это выглядит как разумный подход, который должен работать в прямом случае.

Возможно, вы захотите посмотреть на вызов 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;
}

Обратите внимание, что если вы хотите, чтобы дочерние отношения были strict (т. Е. Каталог не являлся дочерним для себя), вы можете изменить начальное назначение child в строке 9 на child.getParentFile(), поэтому первая проверка выполняется в содержащем дочерний каталог.

11
Andrzej Doyle

Это будет работать для вашего примера. Он также вернет true, если дочерний объект является относительным путем (Что часто желательно.)

boolean myCheck(File maybeChild, File possibleParent)
{
    URI parentURI = possibleParent.toURI();
    URI childURI = maybeChild.toURI();
    return !parentURI.relativize(childURI).isAbsolute();
}
7
finnw

Это, вероятно, будет работать нормально, хотя я бы использовал getCanonicalPath(), а не getAbsolutePath(). Это должно нормализовать любые странные пути, такие как x/../y/z, которые в противном случае испортили бы соответствие.

4
skaffman
maybeChild.getCanonicalPath().startsWith( possibleParent.getCanonicalPath() );
2
user1988293

Будьте в курсе относительных путей! Я думаю, что самое простое решение - что-то вроде этого:

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)
1
Ľubomír Varga

Старый вопрос, но решение до 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);
}
0
Mattias Isegran Bergander