Подтвердить что ты не робот

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

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

Скажите c:\Program Files\My Company\test\My App - возможный дочерний элемент c:\Program Files.

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

boolean myCheck(File maybeChild, File possibleParent)
{
    return maybeChild.getAbsolutePath().startsWith( possibleParent.getAbsolutePath());
}
4b9b3361

Ответ 1

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

Ответ 2

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

Ответ 3

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

Возможно, вам захочется взглянуть на вызов 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;
}

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

maybeChild.getCanonicalPath().startsWith( possibleParent.getCanonicalPath() );

Ответ 7

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

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)

Ответ 8

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

Ответ 9

Удивительно, но не существует простого, но функционального решения.

Принятый ответ считает те же каталоги дочерними, что неверно.

Вот пример использования только API java.nio.file.Path:

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();
}