# File Attribut bzw Link erkennen



## harmolodic (9. Okt 2010)

Hallo,

ich möchte rekursiv alle Datei Verzeichnisseinträge erreichen.

Bei Verzeichnis Einträgen die ein Link sind ist das problematisch (u.U. unendlich).

Mit File.list() lese ich ein Verzeichnis, prüfe mit isDirectory() ob es sich um Datei oder Verzeichnis handelt und lese in den erhaltenen Verzeichnissen weiter.

In der Linux Shell zeigt z.B.:


```
#ls .wine/dosdevices/ -l

lrwxrwxrwx 1 ed ed  8 12. Sep 14:48 d:: -> /dev/hdc
```
Der Link ist am führenden "l" in "lrwxrwxrwx" erkennbar.

Die Mehtode File.isDirectory() sagt hier das es sich um ein Verzeichnis handelt. Es wird scheins der Link direkt aufgelöst, ich würde aber gerne erfahren ob es sich um einen Link handelt, und ggf. wie sein Ziel lautet.

Wie kann ich erkennen das es sich hier um einen Link handelt?.

Andere Datei Atribute isFile(), canWrite(), canRead(), canExecute() helfen hier nicht weiter. Eine Methode isLink() hat File scheins nicht.


----------



## LoR (9. Okt 2010)

Probier mal das:


```
import java.io.File;
import sun.awt.shell.ShellFolder;
...
ShellFolder shellFolder = ShellFolder.getShellFolder(new File("xyz.dat"));
if(shellFolder.isLink()) {
  //do something
}
...
```

Es handelt sich hierbei aber um eine undokumentierte Funktion aus dem JDK.


----------



## harmolodic (9. Okt 2010)

Danke,

gerade probiert, laut Galileo Computing :: Java ist auch eine Insel (8. Auflage) – 14 Dateien und Datenströme funktioniert das für Windows mit .lnk Dateien.

Bei mir wird wird der Link nicht erkannt, die Methoden bringen:

```
FolderTyp:File Folder
isLink:false
FolderLocation:null
```

Bei gewöhnlichen Verzeichnissen wird das auch zurück gegeben.


----------



## LoR (10. Okt 2010)

Ich habe den folgenden Code mal schnell zusammengehackt. Ich vermute aberes auch nicht besser funktioniert, da "ShellFolder" das wahrscheinlich auch nicht viel anders macht.
Probiers trotzdem mal.


```
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.channels.FileChannel;
import java.util.Arrays;

public class WindowsShellLink {

    //magic number
    private static final int[] CLSID = {0x00021401, 0x00000000, 0x000000C0, 0x46000000};
    private static final int BYTES = 20;

    private final int[] COMPARABLE_CLSID = new int[4];
    private final ByteBuffer buffer;

    public WindowsShellLink() {
        buffer = ByteBuffer.allocate(BYTES);
        buffer.order(ByteOrder.LITTLE_ENDIAN);
    }

    public boolean isLink(File linkfile) throws IOException {
        Arrays.fill(COMPARABLE_CLSID, 0);
        buffer.clear();
        FileInputStream fstream = null;
        FileChannel channel = null;
        try {
            fstream = new FileInputStream(linkfile);
            channel = fstream.getChannel();
            read(channel);
        } finally {
            if (fstream != null) {
                fstream.close();
            }
            if (channel != null) {
                channel.close();
            }
        }
        return Arrays.equals(CLSID, COMPARABLE_CLSID);
    }

    private void read(FileChannel channel) throws IOException {
        if(channel.size() < BYTES) {
            return;
        }
        channel.read(buffer);
        buffer.flip();
        IntBuffer iBuffer = buffer.asIntBuffer();
        iBuffer.get(); //ignore
        iBuffer.get(COMPARABLE_CLSID);
    }
}
```


```
public static void main(String[] args) throws IOException {
        File dir = new File("C:\\myDirectory\\");
        File[] files = dir.listFiles();
        WindowsShellLink wsl = new WindowsShellLink();
        for (File file : files) {
            System.out.println(file.getName() + " " + wsl.isLink(file));
        }
    }
```


//EDIT
Falls das JDK 7 (OpenJDK 6 oder 7) für dich kein Problem darstellt, dann verwende die Funktionalitäten die dort bereitgestellt werden. Schau dir mal die Funktionen des java.nio.file - Packages an. Dort kannst du sowohl SymbolicLinks als auch HardLinks erstellen und testen.


----------



## harmolodic (11. Okt 2010)

Danke für den Code,

habe ihn ausprobiert, unter Linux erkennt er den Link nicht als Link, aber für Windows werde ich ihn evt. verwenden.

Gut ist auch der Tip sich JDK 7 (OpenJDK 6 oder 7) anzuschauen.

Mit dem Package File lässt sich ein Link daran erkennen das sich File.getAbsoluteFile(), das den absoluten Pfad anzeigt, von File.getCanonicalFile(), das das Linkziel zeigt, unterscheidet.

Die folgende Methode erkennt einen Link unter Linux, sie verwendet jedoch String.equals(String) was viel Performanz kostet.


```
public static boolean isLink(File file) {
        String cPath = "";
        try {
            cPath = file.getCanonicalPath();
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
        return !cPath.equals(file.getAbsolutePath());
    }
```
Sobald ich eine bessere Lösung gefunden habe werde ich sie hier posten. Anderen Ansätze bleiben willkommen.


----------



## LoR (11. Okt 2010)

Bzgl. JDK 7 (Open JDK 6 und 7)

Benutz statdesse die Funktionalitäten aus dem NIO 2 -Package:
Links, Symbolic or Otherwise (The Java™ Tutorials > Essential Classes > Basic I/O)


----------

