¿Cómo verificar si una ruta dada es posible que sea hija de otra ruta?

4 minutos de lectura

Avatar de usuario de Jayan
Jayán

Estoy tratando de encontrar si la ruta dada es posible que sea hija de otra ruta usando Java. Ambas rutas pueden no existir.

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

Actualmente estoy haciendo esto con

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

Avatar de usuario de Jecho Jekov
Jecho Jekov

También puedes usar java.nio.file.Path para hacer esto mucho más fácilmente. El java.nio.file.Path.startsWith método 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, "");
}

Producción:

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

Si necesita más confiabilidad, puede usar toRealPath en lugar de toAbsolutePath.

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

    –Tim Bender

    04/06/2013 a las 17:56

  • ¿Cómo maneja esto las rutas con .. ¿en ellos?

    – Máx.

    25 de noviembre de 2015 a las 9:07

  • El método “toAbsolutePath” resuelve “..” dentro de la ruta, por lo que debería funcionar. Aunque mejor probarlo.

    – Jecho Jekov

    25 de noviembre de 2015 a las 12:47

  • en realidad tuve que usar Paths.get(parentText).normalize() para manejar adecuadamente ... toAbsolutePath() no los resolvió, y toRealPath() lanza una IOException si el archivo no existe. Esto funcionó en OSX y Centos 6.7 usando Java 7.

    – Matt D.

    15 de marzo de 2017 a las 15:59

  • Esto parece verificar solo los directorios bajo la raíz, ¿qué pasa con la Carpeta B, no debería ser también un padre?

    –Calvin Taylor

    15 de septiembre de 2020 a las 16:14

avatar de usuario de biziclop
bizcocho

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

  • Esta parece la mejor solución. ¿Tiene agujeros?

    – Grumosaurio

    20 de marzo de 2019 a las 3:52


  • @JoshuaD No es un agujero per se, pero devolverá falso cuando se pruebe contra possibleParent sí mismo. Esto podría ser lo que se desea o no, según el caso de uso. (Por ejemplo, probar rutas para ver si están contenidas en un árbol de directorios permitido, esto fallaría en la raíz de ese árbol).

    – Ti Strga

    25 de febrero de 2021 a las 16:45

Avatar de usuario de Andrzej Doyle
andrzej doyle

Aparte del hecho de que las rutas pueden no existir (y la canonicalización puede no tener éxito), este parece un enfoque razonable que debería funcionar en el caso sencillo.

Es posible que desee considerar llamar getParentFile() en el “tal vez niño” 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 secundaria sea estricto (es decir, un directorio no es un hijo de sí mismo) puede cambiar la inicial child asignación en la línea 9 para ser child.getParentFile() entonces la primera verificación ocurre en el directorio contenedor del niño.

  • +1 Aunque OP no lo indicó, es probable que la pregunta se relacione con archivos reales existentes y no con rutas.

    – biziclop

    20 de enero de 2011 a las 11:54

avatar de usuario de finnw
finlandés

Esto funcionará para su ejemplo. también volverá 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();
}

Eso probablemente funcionará bien tal como está, aunque yo usaría getCanonicalPath() en vez de getAbsolutePath(). Esto debería normalizar cualquier ruta extraña como x/../y/z que de otro modo estropearía la coincidencia.

  • no, no, esto es no ¡correcto! el del interrogador myCheck() método, incluso cuando se canonicaliza, dirá falsamente que C:\Prog es un hijo de C:\Program Files. Vea la respuesta a continuación por @biziclop.

    –Matt Quigley

    14/08/2012 a las 19:00

Avatar de usuario de Hosam Aly
hosam aly

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

  • no, no, esto es no ¡correcto! el del interrogador myCheck() método, incluso cuando se canonicaliza, dirá falsamente que C:\Prog es un hijo de C:\Program Files. Vea la respuesta a continuación por @biziclop.

    –Matt Quigley

    14/08/2012 a las 19:00

Avatar de usuario de Ľubomír Varga
Ľubomír Varga

¡Tenga en cuenta las rutas relativas! Creo que la 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 puedes tener un 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)

¿Ha sido útil esta solución?