2011-01-20 15 views
32

Estoy tratando de encontrar si el camino dado es posible hijo de otro camino usando java. Ambos caminos pueden no existir.¿Cómo comprobar si un camino determinado es posible hijo de otro camino?

Diga c:\Program Files\My Company\test\My App es un hijo posible de c:\Program Files.

Actualmente estoy haciendo esto con

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

¿Esto requerirá ejemplo de sistema de archivos IO en absoluto? – user2586917

+0

Posible duplicado de [Java: compruebe si la ruta es principal de un archivo] (http://stackoverflow.com/questions/28698125/java-check-if-path-is-parent-of-a-file) – Suma

+0

@Suma : La pregunta que enlazó es _duplicate_ de esto. – Jayan

Respuesta

41

También puede utilizar java.nio.file.Path hacer esto mucho más fácil. El método java.nio.file.Path.startsWith parece manejar todos los casos posibles.

Ejemplo:

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, ""); 
} 

salidas

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

Si necesita más fiabilidad puede utilizar "toRealPath" en lugar de "toAbsolutePath".

+1

Gran solución. Solo es posible en Java 7 o posterior. –

+1

¿Cómo maneja esto las rutas con '..' en ellas? – Max

+0

El método "toAbsolutePath" resuelve ".." dentro de la ruta, por lo que debería funcionar. Mejor prueba, sin embargo. –

4

que probablemente funciona bien como está, aunque me gustaría utilizar getCanonicalPath() en lugar de getAbsolutePath(). Esto debería normalizar cualquier ruta extraña como x/../y/z que de otra manera arruinaría el emparejamiento.

+1

¡Muchas gracias por la solución rápida y corregida! – Jayan

+9

No, no, esto es ** no ** correcto! El método 'myCheck()' de la persona que pregunta, incluso cuando se canonicaliza, falsamente dirá que 'C: \ Prog' es hijo de' C: \ Program Files'. Consulte la respuesta a continuación por @biziclop. –

7

Esto funcionará para su ejemplo. También regresará true si el niño es una ruta relativa (que a menudo es deseable.)

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)) dice, _ "Si [dado URI no es un niño] entonces se devuelve el URI dado. "_ Lo que significa que es mejor cambiar tu cheque a' parentURI.relativize (childURI)! = childURI'. De lo contrario, su función da un falso positivo si el 'maybeChild' es una ruta absoluta. – SnakE

+0

tienes razón. Probablemente quise decir que si 'maybeChild' fuera _relativo_ pero no un hijo de' posibleParent', tu método aún devolvería 'true'. Pero esto no es realmente un problema porque 'File.toURI()' garantiza que devolverá un URI absoluto, de modo que 'childURI' siempre será absoluto. Aún así, el cheque que propuse debería funcionar bien también. – SnakE

+0

si 'maybeChild' es relativo, entonces potencialmente puede ser hijo de cualquier cosa, no se puede decir. – finnw

10

apartes del hecho de que no pueden existir los caminos (y el canonicalisation puede no tener éxito), esto parece una razonable enfoque que debería funcionar en el caso simple.

Es posible que desee ver llamando al getParentFile() en el "quizás hijo" en un bucle, probando si coincide con el padre en cada paso. También puede cortocircuitar la comparación si el padre no es un directorio (real).

Tal vez algo como lo siguiente:

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

Tenga en cuenta que si desea que la relación niño sea estricta (es decir, un directorio no es un hijo de la misma) se puede cambiar el child asignación inicial en la línea 9 para ser child.getParentFile() por lo que el primer control se realiza en el directorio que contiene el niño.

+2

+1 Aunque OP no lo indicó, es probable que la pregunta se relacione con los archivos existentes y no con las rutas. – biziclop

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

maybeChild.getCanonicalPath(). StartsWith (possibleParent.getCanonicalPath());

1

¡Tenga en cuenta las rutas relativas! Creo que solución más simple es algo como esto:

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

en Scala que puede tener enfoque similar:

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

pregunta Viejo pero un pre-1.7 solución:

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

Para completar la solución de 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); 
}