2011-01-20 2 views
32

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

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

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

boolean myCheck(File maybeChild, File possibleParent) 
{ 
    return maybeChild.getAbsolutePath().startsWith(possibleParent.getAbsolutePath()); 
} 
+0

ли этот пример требует файловой системы ввода-вывода на всех? – user2586917

+0

Возможный дубликат [Java: проверьте, является ли путь родителем файла] (http://stackoverflow.com/questions/28698125/java-check-if-path-is-parent-of-a-file) – Suma

+0

@Suma : Вопрос, который вы связали, является _duplicate_ этого. – Jayan

ответ

41

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

+1

Отличное решение. Возможно только в Java 7 или новее. –

+1

Как это обрабатывает пути с '..' в них? – Max

+0

Метод «toAbsolutePath» разрешает «..» внутри пути, поэтому он должен работать. Лучше протестируйте его. –

4

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

+1

Большое спасибо за быстрое и исправленное решение! – Jayan

+9

Нет, нет, это ** не ** правильно! Метод 'myCheck()' автора вопроса, даже когда canonicalized, ложно скажет, что 'C: \ Prog' является дочерним элементом' C: \ Program Files'. См. Ответ ниже @biziclop. –

7

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

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

[Spec] (http://docs.oracle.com/javase/1.4.2/docs/api/java/net/URI.html#relativize (java.net.URI)) говорит: «Если [данный URI не является потомком], тогда возвращается данный URI ». Это означает, что, вероятно, лучше изменить свою проверку на' parentURI.relativize (childURI)! = childURI'. В противном случае ваша функция дает ложное положительное значение, если 'maybeChild' является абсолютным путем. – SnakE

+0

Вы правы. Вероятно, я хотел сказать, что если 'maybeChild' были _relative_, но не дочерним элементом' possibleParent', ваш метод все равно вернул бы «true». Но на самом деле это не проблема, потому что 'File.toURI()' гарантированно возвращает абсолютный URI, так что 'childURI' всегда является абсолютным. Тем не менее, чек, который я предложил, также должен работать нормально. – SnakE

+0

, если 'maybeChild' относительный, то он потенциально может быть ребенком чего-либо - вы не можете сказать. – finnw

10

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

Возможно, вы захотите взглянуть на вызов 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(), поэтому первая проверка происходит в директории, содержащей дочерний элемент.

+2

+1 Хотя ОП не заявлял об этом, но действительно, вероятно, вопрос связан с фактическими, существующими файлами, а не с путями. – biziclop

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

maybeChild.getCanonicalPath(). StartsWith (возможноParent.getCanonicalPath());

1

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

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

В Скале вы можете иметь подобный подход:

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) 
0

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