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());
}
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ó, ytoRealPath()
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
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
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
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 queC:\Prog
es un hijo deC:\Program Files
. Vea la respuesta a continuación por @biziclop.–Matt Quigley
14/08/2012 a las 19:00
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 queC:\Prog
es un hijo deC:\Program Files
. Vea la respuesta a continuación por @biziclop.–Matt Quigley
14/08/2012 a las 19:00
Ľ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)