J'essaie de trouver si le chemin donné est un enfant possible d'un autre chemin en utilisant Java. Les deux chemins peuvent ne pas exister.
Dites que c:\Program Files\My Company\test\My App
est un enfant possible de c:\Program Files
.
Actuellement je le fais avec
boolean myCheck(File maybeChild, File possibleParent)
{
return maybeChild.getAbsolutePath().startsWith( possibleParent.getAbsolutePath());
}
Vous pouvez également utiliser Java.nio.file.Path pour le faire beaucoup plus facilement. La méthode Java.nio.file.Path.startsWith semble traiter tous les cas possibles.
Exemple:
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, "");
}
les sorties
/FolderA/FolderB/File = true
/FolderA/FolderB/F = false
/FolderA/FolderB = true
/FolderA/Folder = false
/FolderA = true
/Folder = false
/ = true
= false
Si vous avez besoin de plus de fiabilité, vous pouvez utiliser "toRealPath" au lieu de "toAbsolutePath".
File parent = maybeChild.getParentFile();
while ( parent != null ) {
if ( parent.equals( possibleParent ) )
return true;
parent = parent.getParentFile();
}
return false;
Mis à part le fait que les chemins peuvent ne pas exister (et que la canonisation peut ne pas aboutir), cela semble être une approche raisonnable qui devrait fonctionner dans le cas simple.
Vous voudrez peut-être appeler getParentFile () sur "peut-être l'enfant" dans une boucle, en vérifiant si cela correspond au parent à chaque étape. Vous pouvez également court-circuiter la comparaison si le parent n'est pas un répertoire (réel).
Peut-être quelque chose comme ce qui suit:
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;
}
Notez que si vous souhaitez que la relation enfant soit strict (c’est-à-dire qu’un répertoire n’est pas un enfant en lui-même), vous pouvez modifier l’affectation initiale child
de la ligne 9 par child.getParentFile()
pour que le premier contrôle ait lieu annuaire.
Cela fonctionnera pour votre exemple. Il retournera également true
si l'enfant est un chemin relatif (Ce qui est souvent souhaitable.)
boolean myCheck(File maybeChild, File possibleParent)
{
URI parentURI = possibleParent.toURI();
URI childURI = maybeChild.toURI();
return !parentURI.relativize(childURI).isAbsolute();
}
Cela fonctionnera probablement tel quel, bien que j'utiliserais getCanonicalPath()
plutôt que getAbsolutePath()
. Cela devrait normaliser tous les chemins étranges comme x/../y/z
qui autrement bousillerait la correspondance.
maybeChild.getCanonicalPath().startsWith( possibleParent.getCanonicalPath() );
Soyez conscient des chemins relatifs! Je pense que la solution la plus simple ressemble à ceci:
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, vous pouvez avoir une approche similaire:
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)
Ancienne question mais solution antérieure à la 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;
}
Pour être complet, la solution 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);
}