2011-01-20 12 views
32

Sto cercando di trovare se percorso dato è possibile figlio di un altro percorso utilizzando java. Entrambi i percorsi potrebbero non esistere.Come verificare se un dato percorso è possibile figlio di un altro percorso?

Dire c:\Program Files\My Company\test\My App è un possibile figlio di c:\Program Files.

Attualmente sto facendo questo con

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

Fa questo esempio richiedere filesystem IO a tutti? – user2586917

+0

Possibile duplicato di [Java: verifica se il percorso è padre di un file] (http://stackoverflow.com/questions/28698125/java-check-if-path-is-parent-of-a-file) – Suma

+0

@Suma : La domanda che hai collegato è _duplicate_ di questo. – Jayan

risposta

41

È inoltre possibile utilizzare java.nio.file.Path per fare questo molto più facilmente. Il metodo java.nio.file.Path.starts con il metodo sembra gestire tutti i possibili casi.

Esempio:

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

uscite

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

Se avete bisogno di più affidabilità è possibile utilizzare "toRealPath" invece di "toAbsolutePath".

+1

Ottima soluzione. Possibile solo in Java 7 o versioni successive. –

+1

In che modo gestisce i percorsi con '..' in essi? – Max

+0

Il metodo "toAbsolutePath" risolve ".." all'interno del percorso, quindi dovrebbe funzionare. Meglio testarlo però. –

4

che probabilmente funziona bene così com'è, anche se io userei getCanonicalPath() piuttosto che getAbsolutePath(). Questo dovrebbe normalizzare qualsiasi percorso strano come x/../y/z che altrimenti rovinerebbe la corrispondenza.

+1

Mille grazie per la soluzione rapida e corretta! – Jayan

+9

No, no, questo è ** non ** corretto! Il metodo 'myCheck()' del questionario, anche quando canonicalizzato, dirà falsamente che 'C: \ Prog' è figlio di' C: \ Programmi '. Vedi la risposta sotto di @biziclop. –

7

Questo funzionerà per il tuo esempio. Sarà anche tornare true se il bambino è un percorso relativo (che è spesso desiderabile.)

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, _ "Se [dato URI non è un bambino] quindi viene restituito l'URI dato. "_ Significa che è probabilmente meglio cambiare il controllo in' parentURI.relativize (childURI)! = childURI'. Altrimenti la tua funzione dà un falso positivo se 'maybeChild' è un percorso assoluto. – SnakE

+0

hai ragione. Probabilmente intendevo dire che se 'maybeChild' fosse _relative_ ma non figlio di' possibleParent', il metodo restituirà 'true'. Ma questo non è in realtà un problema perché 'File.toURI()' è garantito per restituire un URI assoluto, in modo che 'childURI' sia sempre assoluto. Tuttavia, l'assegno che ho proposto dovrebbe funzionare egregiamente. – SnakE

+0

se 'maybeChild' è relativo allora può potenzialmente essere figlio di qualsiasi cosa - non si può dire. – finnw

10

Divagazioni dal fatto che non può esistere i percorsi (e la canonicalizzazione potrebbe non avere successo), questo sembra un ragionevole approccio che dovrebbe funzionare nel caso semplice.

Si consiglia di guardare getParentFile() sul "forse bambino" in un ciclo, testando se corrisponde al genitore in ogni passaggio. È anche possibile cortocircuitare il confronto se il genitore non è una directory (reale).

Forse qualcosa di simile al seguente:

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

Si noti che se si desidera che il rapporto bambino ad essere rigorosa (vale a dire una directory non è un figlio di se stesso) è possibile modificare l'iniziale child assegnazione on line 9 per essere child.getParentFile() quindi il primo controllo si verifica nella directory contenente del figlio.

+2

+1 Sebbene OP non lo abbia indicato, ma in effetti è probabile che la domanda riguardi file effettivi, esistenti e non percorsi. – 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

Attenzione ai percorsi relativi! Penso che la soluzione più semplice è qualcosa di simile:

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

a Scala si può avere approccio simile:

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

vecchia questione, ma un pre-1.7 Soluzione:

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

Per completezza java 1.7+ soluzione:

public boolean startsWith(String possibleRoot, String possibleChildOrSame) { 
     Path p1 = Paths.get(possibleChildOrSame).toAbsolutePath(); 
     Path p2 = Paths.get(possibleRoot).toAbsolutePath(); 
     return p1.startsWith(p2); 
} 
Problemi correlati