File Attribut bzw Link erkennen

harmolodic

Mitglied
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.:

Code:
#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.
 
Zuletzt bearbeitet:
Probier mal das:

Java:
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.
 
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.

Java:
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);
    }
}

Java:
    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.
 
Zuletzt bearbeitet:
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.

Java:
    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.
 
Zuletzt bearbeitet:

Zurück
Oben