2009-05-01 19 views
39

In una classe DirectoryWalker, desidero scoprire se un'istanza File è in realtà un collegamento simbolico a una directory (supponendo che il walker cammini su sistemi UNIX). Dato, so già che l'istanza è una directory, sarebbe la seguente condizione affidabile per determinare il collegamento simbolico?Java 1.6: determinare i collegamenti simbolici

File file; 
// ...  
if (file.getAbsolutePath().equals(file.getCanonicalPath())) { 
    // real directory ---> do normal stuff  
} 
else { 
    // possible symbolic link ---> do link stuff 
} 
+0

Correlato a http://stackoverflow.com/questions/2175673/java-check-symbolic-link-file-existence – Gray

+6

Java 1.7: [java.nio.Files.isSymbolicLink (Percorso)] (http: // docs .oracle.com/javase/7/docs/api/java/nio/file/Files.html # isSymbolicLink% 28java.nio.file.Path% 29) - più una nota per me stesso - Continuo a finire qui! –

risposta

45

La tecnica utilizzata in Apache Commons utilizza il percorso canonico per la directory padre, non il file stesso. Non penso che tu possa garantire che una mancata corrispondenza sia dovuta a un collegamento simbolico, ma è una buona indicazione che il file richiede un trattamento speciale.

Questo è Apache code (soggetto a their license), modificato per compattezza.

public static boolean isSymlink(File file) throws IOException { 
    if (file == null) 
    throw new NullPointerException("File must not be null"); 
    File canon; 
    if (file.getParent() == null) { 
    canon = file; 
    } else { 
    File canonDir = file.getParentFile().getCanonicalFile(); 
    canon = new File(canonDir, file.getName()); 
    } 
    return !canon.getCanonicalFile().equals(canon.getAbsoluteFile()); 
} 
+0

Hmm, Gray ed erickson: in effetti sembra funzionare bene anche se si collega a un file nella stessa directory. Hai un test unitario che illustra il tuo punto? – Kutzi

+6

Questo non funziona su Windows con NTFS (quando symlink viene creato con mklink). – Ben

13

Java 1.6 non fornisce un accesso di livello così basso al file system. Sembra che NIO 2, che dovrebbe essere incluso in Java 1.7, abbia il supporto per i collegamenti simbolici. A draft of the new API è disponibile. I collegamenti simbolici are mentioned there, creating e following sono possibili. Non sono esattamente sicuro che quale metodo debba essere usato per scoprire se un file è un collegamento simbolico. C'è lo a mailing list per discutere di NIO 2 - forse lo sapranno.

5

Sembra che getCanonicalPath() possa fare altre cose che potrebbero renderlo diverso dal percorso assoluto.

Questo metodo converte prima questo percorso in forma assoluta, se necessario, come se invocando il metodo getAbsolutePath(), quindi lo associa alla sua forma univoca in modo dipendente dal sistema. Questo in genere comporta la rimozione di nomi ridondanti come "." e ".." dal percorso, risoluzione dei collegamenti simbolici (su piattaforme UNIX) e conversione di lettere di unità in un caso standard (su piattaforme Microsoft Windows).

Ma potrebbe funzionare per la maggior parte dei casi d'uso; il tuo chilometraggio può variare.

1

dispiace per rispondere a un vecchio post tale, ma ero alla ricerca di una soluzione per i sistemi Windows qualche tempo fa, e alcune delle risposte precedenti non ha funzionato per me. Se non ti interessa la compatibilità multipiattaforma e hai solo bisogno di una soluzione per Windows, la seguente tecnica ha funzionato bene per i miei scopi.

File f = new File("whatever file or folder"); 
if (f instanceof ShellFolder) { 
    ShellFolder sf = (ShellFolder)f; 
    if (sf.isLink()) { 
    // Your code when it's a link 
    } 
} 
+1

'ShellFolder' sembra essere' sun.awt.shell.ShellFolder' in 'rt.jar' – sjngm

+1

Non penso che" new File() "produrrà un'istanza di ShellFolder in modo dinamico. Funziona come conseguenza di FileChoser. – eckes

-2

Ho pensato di condividere la buona fortuna che avevo con questo problema. Sto usando JDK 1.6.0_23 e quindi non posso beneficiare di NIO2. Sto costruendo e girando su Windows 7/x64 SOLO, quindi il chilometraggio può variare in altri ambienti. Sfortunatamente, altre soluzioni qui non hanno funzionato per evitare le NullPointerException causate durante il tentativo di attraversare una giunzione (probabilmente perché junction! = Symlink ....). Mentre non sono vincolato dalla versione di JDK, ho deciso di mantenere il problema ancora per un po '.

Avevo questo codice che causerebbe un NullPointerException se utilizzato su un collegamento simbolico o quando si incontra la directory 'System Volume Information'. (Nota, traverseItem.f() restituisce un oggetto di tipo java.io.File)

if (traverseItem.f().isDirectory) { 
    for (File item : traverseItem.f().listFiles()) { 

Quindi, è presumibilmente una directory, ma chiamando ListFiles() su di esso provoca un NPE. Cosa fare? Ho spiato il metodo list() e mi chiedevo se avrebbe mostrato lo stesso comportamento.Quello che ho scoperto è stato il seguente:

La lista di chiamate() su un file che descrive una cartella vuota restituisce una stringa [] di lunghezza zero. Tuttavia, la lista() in un file che descrive un incrocio che altrimenti andare in crash da ListFiles() chiamando restituisce null

sono stato in grado di evitare le NullPointerExceptions aggiungendo il seguente test prima di chiamare ListFiles()

String[] contents = traverseItem.f().list(); 
    if (contents != null) { //Non-traversible if null, possibly junction or ??? 

Resta da testare in modo esaustivo tutti i casi di giunzione, collegamento simbolico, hard link e oserei menzionarlo, scorciatoia, ma questo può aiutare alcuni.

+0

La tua spiegazione è dappertutto, sembra quasi del tutto irrilevante nella maggior parte dei casi, per la maggior parte inaccurata in altri, e i frammenti di codice sono enormemente incompleti. Darei questo 2 downvotes se potessi. – searchengine27

11

Inoltre, guardare fuori per file.isFile() e file.isDirectory() entrambi i risultati che ritornano in base al file risolto e quindi sia il ritorno false quando file si riferisce ad un link simbolico in cui la destinazione non esiste.

(so che questo non è una risposta utile in sé, ma mi ha inciampato un paio di volte quindi ho pensato che avrei dovuto condividere)

+0

Non avrei mai considerato questo scenario. Bella menzione. – kevinarpe

3

Se sei già la codifica qualcosa di specificamente per * nix, allora si potrebbe fare un comando shell di Java come questo:

Questo è molto specifico per * nix, ma funziona almeno.

Problemi correlati