2009-05-01 31 views
39

En una clase DirectoryWalker, quiero saber si una instancia de File es realmente un enlace simbólico a un directorio (suponiendo que el walker camine en sistemas UNIX). Dado que ya sé que la instancia es un directorio, ¿sería la siguiente una condición confiable para determinar el enlace simbólico?Java 1.6 - determinar enlaces simbólicos

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

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

+6

Java 1.7: [java.nio.Files.isSymbolicLink (Path)] (http: // docs .oracle.com/javase/7/docs/api/java/nio/file/Files.html # isSymbolicLink% 28java.nio.file.Path% 29) - más una nota para mí - ¡sigo terminando aquí! –

Respuesta

45

La técnica utilizada en Apache Commons utiliza la ruta canónica al directorio principal, no el archivo en sí. No creo que pueda garantizar que una discrepancia se deba a un enlace simbólico, pero es una buena indicación de que el archivo necesita un tratamiento especial.

Esto es Apache code (sujeto a their license), modificado para compacidad.

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 y erickson: de hecho, parece funcionar bien incluso si se vincula a un archivo en el mismo directorio. ¿Tiene una prueba de unidad que ilustra su punto? – Kutzi

+6

Esto no funciona en Windows con NTFS (cuando el enlace simbólico se crea con mklink). – Ben

13

Java 1.6 no proporciona dicho acceso de bajo nivel al sistema de archivos. Parece que NIO 2, que debe incluirse en Java 1.7, tendrá soporte para enlaces simbólicos. A draft of the new API está disponible. Los enlaces simbólicos are mentioned there, creating y following ellos son posibles. No estoy exactamente seguro de qué método debería usarse para averiguar si un archivo es un enlace simbólico. Hay a mailing list para hablar de NIO 2, tal vez lo sabrán.

5

Parece que getCanonicalPath() puede hacer otras cosas que pueden hacer que sea diferente de la ruta absoluta.

Este método primero convierte esta ruta de acceso a forma absoluta si es necesario, como si invoca el método getAbsolutePath() y luego lo asocia a su forma única de una manera dependiente del sistema. Esto generalmente implica eliminar nombres redundantes como "." y ".." desde la ruta, resolviendo enlaces simbólicos (en plataformas UNIX) y convirtiendo letras de unidad en un caso estándar (en plataformas Microsoft Windows).

Pero podría funcionar para la gran mayoría de sus casos de uso; Su experiencia puede ser diferente.

1

este momento a responder a un antiguo puesto de este tipo, pero yo estaba buscando una solución para los sistemas Windows hace algún tiempo, y algunas de las respuestas anteriores no funcionó para mí. Si no está interesado en la compatibilidad multiplataforma y solo necesita una solución para Windows, la siguiente técnica funcionó bien para mis propósitos.

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' parece ser' sun.awt.shell.ShellFolder' en 'rt.jar' – sjngm

+1

No creo que" new File() "produzca una instancia de ShellFolder dinámicamente. Funciona como resultado de FileChoser. – eckes

-2

Pensé que podría compartir algo de buena suerte que tuve al tratar este problema. Estoy usando JDK 1.6.0_23 y no puedo beneficiarme de NIO2. Estoy compilando y ejecutando SOLAMENTE Windows 7/x64, por lo que el kilometraje puede variar en otros entornos. Lamentablemente, otras soluciones aquí no me funcionaron para evitar las NullPointerExceptions causadas cuando intentaba atravesar un cruce (probablemente porque junction! = Symlink ....). Si bien no estoy limitado por la versión JDK, decidí seguir con el problema un poco más.

Tenía este código que causaría una NullPointerException si se usa en un enlace simbólico o cuando se encuentra con el directorio 'System Volume Information'. (Nota, traverseItem.f() devuelve un objeto de tipo java.io.File)

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

lo tanto, es supuestamente un directorio pero llamar listFiles() sobre ella provoca un NPE. ¿Qué hacer? Espié el método list() y me pregunté si mostraría el mismo comportamiento.Lo que descubrí fue lo siguiente:

La lista de llamadas() en un archivo que describe una carpeta vacía devuelve una matriz String [] de longitud cero. Sin embargo, la lista() en un archivo que describe una unión que de otro modo chocar de listFiles() llamando devuelve null

yo era capaz de evitar los NullPointerExceptions mediante la adición de la siguiente prueba antes de llamar listFiles()

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

Queda por probar exhaustivamente todos los casos de unión, enlace simbólico, enlace rígido, y me atrevo a mencionarlo, atajo, pero esto puede ayudar a algunos.

+0

Su explicación está por todas partes, parece casi completamente irrelevante en la mayoría de los lugares, en su mayoría inexacta en otros, y sus fragmentos de código son masivamente incompletos. Yo daría estos 2 votos a favor si pudiera. – searchengine27

11

También, ten cuidado con file.isFile() y file.isDirectory() ambos resultados regresan basados ​​en el archivo resuelto y, por tanto, tanto volver false cuando file se refiere a un enlace simbólico donde no existe el objetivo.

(sé que esto no es una respuesta útil en sí mismo, pero me tropecé un par de veces, así que pensé que debería compartir)

+0

Nunca hubiera considerado este escenario. Buena mención. – kevinarpe

3

Si ya está codificando algo específicamente para * nix, entonces usted podría hacer un comando de shell de Java como este:

Process p = Runtime.getRuntime().exec(new String[]{"test", "-h", yourFileName}); 
p.waitFor(); 
if (p.exitValue() == 0) 
    System.out.println("This file is a symbolic link"); 
else 
    System.out.println("This file is not a symbolic link"); 

Eso es muy específico para * nix, pero al menos funciona.

Cuestiones relacionadas