2012-05-21 7 views
10

Ich versuche eine Möglichkeit zu finden, zu erkennen, wenn ein Flash-Laufwerk an meinen Computer angeschlossen wurde. Bisher war die Lösung, die ich fand, FileSystem#getFileStores für Änderungen abzufragen. Dies sagt mir zwar, wann das Flash-Laufwerk eingelegt wurde, aber soweit ich das beurteilen kann, gibt es keine Möglichkeit, den Speicherort dafür zu finden. FileStore#type und FileStore#name scheinen beide sehr unzuverlässig, da ihr Rückgabewert implementierungsspezifisch ist, aber sie scheinen die einzigen Methoden zu sein, die möglicherweise relevante Informationen zurückgeben, die bei der Suche nach dem Verzeichnis für FileStore helfen könnten.Finden Sie das Verzeichnis für einen FileStore

, die mit im Auge, der folgende Code:

public class Test { 
    public static void main(String[] args) throws IOException { 
     for (FileStore store : FileSystems.getDefault().getFileStores()) { 
      System.out.println(store); 
      System.out.println("\t" + store.name()); 
      System.out.println("\t" + store.type()); 
      System.out.println(); 
     } 
    } 
} 

Gab mir diese Ausgabe:

/ (/dev/sda5) 
    /dev/sda5 
    ext4 

/* snip */ 

/media/TI103426W0D (/dev/sda2) 
    /dev/sda2 
    fuseblk 

/media/flashdrive (/dev/sdb1) 
    /dev/sdb1 
    vfat 

Wie sich herausstellt, FileStore#type das Format des Antriebs zurück und FileStore#name gibt den Standort von die Gerätedatei für das Laufwerk. Soweit ich feststellen kann, ist die einzige Methode, die den Speicherort des Laufwerks hat, die toString-Methode, aber das Extrahieren des Pfadnamens scheint gefährlich, weil ich nicht sicher bin, wie gut diese bestimmte Lösung anderen Betriebssystemen standhält und zukünftige Versionen von Java.

Gibt es etwas, das mir hier fehlt oder ist das einfach nicht mit Java möglich?

System Information:

$ java -version 
java version "1.7.0_03" 
OpenJDK Runtime Environment (IcedTea7 2.1.1pre) (7~u3-2.1.1~pre1-1ubuntu2) 
OpenJDK Client VM (build 22.0-b10, mixed mode, sharing) 

$ uname -a 
Linux jeffrey-pc 3.2.0-24-generic-pae #37-Ubuntu SMP Wed Apr 25 10:47:59 UTC 2012 i686 athlon i386 GNU/Linux 

Antwort

10

Hier ist eine temporäre Arbeit herum, bis eine bessere Lösung gefunden wird:

public Path getRootPath(FileStore fs) throws IOException { 
    Path media = Paths.get("/media"); 
    if (media.isAbsolute() && Files.exists(media)) { // Linux 
     try (DirectoryStream<Path> stream = Files.newDirectoryStream(media)) { 
      for (Path p : stream) { 
       if (Files.getFileStore(p).equals(fs)) { 
        return p; 
       } 
      } 
     } 
    } else { // Windows 
     IOException ex = null; 
     for (Path p : FileSystems.getDefault().getRootDirectories()) { 
      try { 
       if (Files.getFileStore(p).equals(fs)) { 
        return p; 
       } 
      } catch (IOException e) { 
       ex = e; 
      } 
     } 
     if (ex != null) { 
      throw ex; 
     } 
    } 
    return null; 
} 

Soweit ich weiß, wird diese Lösung nur für Windows- und Linux-Systeme.

Sie haben die IOException in der Windows-Schleife zu fangen, weil, wenn es keine CD in der CD Laufwerk wird eine Ausnahme ausgelöst, wenn Sie versuchen, die FileStore für es abzurufen. Dies kann passieren, bevor Sie über jede Wurzel iterieren.

+0

Funktioniert das wirklich für Windows? Es scheint, als würde es ein Laufwerk verpassen, das ich bei C: \ Data mounte. Der springende Punkt, an dem ich diese neuere API verwende, ist, dass sie mir versprochen hat, alle Mountpunkte und nicht nur die Wurzeln zu finden. – Trejkaz

+0

Auch,/Medien? Meinst du nicht/mnt? – Trejkaz

+0

@Trejkaz Ich wusste nicht, dass du das kannst. Es funktioniert für den Standardfall, in dem Laufwerke als Buchstaben montiert werden. Zumindest unter Ubuntu sind Dinge standardmäßig in/media eingebunden. Sie könnten auch/etc/mtab für eine flexiblere Arbeit auf Linux-Systemen verwenden (ich benutze Windows nicht wirklich, so dass ich kein anderes weiß). – Jeffrey

0

Ich habe nicht wirklich diesen Bereich des Java erforscht, aber ich fand this, die verwandt zu sein scheint. Es verwendet File.listRoots()

Es scheint auch eine Reihe von damit verbundenen Fragen verbunden zu sein.

+1

'File.listRoots' wird nur für Windows arbeiten, und ich habe diese Fragen ohne Erfolg überprüft.Sie wurden alle gefragt, bevor nio2 herauskam – Jeffrey

+0

Ahh> _> Ich werde weiter suchen und diese Antwort bearbeiten, wenn ich irgendetwas finde –

+0

@ Jeffrey es wird nicht einmal für Windows funktionieren, weil unter Windows Sie Laufwerke nicht auf einem Laufwerk montiert haben können Brief. – Trejkaz

4

Dies ist, was ich getan habe. Dies ist auf Windows + UNIX beschränkt, vermeidet jedoch die Verwendung externer Tools oder zusätzlicher Bibliotheksaufrufe. Es stiehlt die Informationen, die Java bereits in FileStore Objekte

LinuxFileStore definitiv erweitert UnixFileStore hat, so wird es funktionieren. Gleiches Angebot für Solaris. Da Mac OS X UNIX ist, funktioniert es wahrscheinlich dort, aber ich bin mir nicht sicher, weil ich seine Unterklasse an keinem Ort sehen konnte, den ich suchte.

public class FileStoreHacks { 
    /** 
    * Stores the known hacks. 
    */ 
    private static final Map<Class<? extends FileStore>, Hacks> hacksMap; 
    static { 
     ImmutableMap.Builder<Class<? extends FileStore>, Hacks> builder = 
      ImmutableMap.builder(); 

     try { 
      Class<? extends FileStore> fileStoreClass = 
       Class.forName("sun.nio.fs.WindowsFileStore") 
        .asSubclass(FileStore.class); 
      builder.put(fileStoreClass, new WindowsFileStoreHacks(fileStoreClass)); 
     } catch (ClassNotFoundException e) { 
      // Probably not running on Windows. 
     } 

     try { 
      Class<? extends FileStore> fileStoreClass = 
       Class.forName("sun.nio.fs.UnixFileStore") 
        .asSubclass(FileStore.class); 
      builder.put(fileStoreClass, new UnixFileStoreHacks(fileStoreClass)); 
     } catch (ClassNotFoundException e) { 
      // Probably not running on UNIX. 
     } 

     hacksMap = builder.build(); 
    } 

    private FileStoreHacks() { 
    } 

    /** 
    * Gets the path from a file store. For some reason, NIO2 only has a method 
    * to go in the other direction. 
    * 
    * @param store the file store. 
    * @return the path. 
    */ 
    public static Path getPath(FileStore store) { 
     Hacks hacks = hacksMap.get(store.getClass()); 
     if (hacks == null) { 
      return null; 
     } else { 
      return hacks.getPath(store); 
     } 
    } 

    private static interface Hacks { 
     Path getPath(FileStore store); 
    } 

    private static class WindowsFileStoreHacks implements Hacks { 
     private final Field field; 

     public WindowsFileStoreHacks(Class<?> fileStoreClass) { 
      try { 
       field = fileStoreClass.getDeclaredField("root"); 
       field.setAccessible(true); 
      } catch (NoSuchFieldException e) { 
       throw new IllegalStateException("file field not found", e); 
      } 
     } 

     @Override 
     public Path getPath(FileStore store) { 
      try { 
       String root = (String) field.get(store); 
       return FileSystems.getDefault().getPath(root); 
      } catch (IllegalAccessException e) { 
       throw new IllegalStateException("Denied access", e); 
      } 
     } 
    } 

    private static class UnixFileStoreHacks implements Hacks { 
     private final Field field; 

     private UnixFileStoreHacks(Class<?> fileStoreClass) { 
      try { 
       field = fileStoreClass.getDeclaredField("file"); 
       field.setAccessible(true); 
      } catch (NoSuchFieldException e) { 
       throw new IllegalStateException("file field not found", e); 
      } 
     } 

     @Override 
     public Path getPath(FileStore store) { 
      try { 
       return (Path) field.get(store); 
      } catch (IllegalAccessException e) { 
       throw new IllegalStateException("Denied access", e); 
      } 
     } 
    } 
} 
+2

Hinweis für andere: Da sich private Felder ohne Vorankündigung ändern können, funktioniert dies nur für die aktuelle Version von Java, bis es anders bestätigt wird. – Jeffrey

+1

Yup. Fügen Sie auf jeden Fall Komponententests hinzu, um zu erkennen, dass sich das Verhalten ändert, wenn Sie dies verwenden. – Trejkaz

-1

Der einfachste Weg, den Einsatz Files.getFileStore(Paths.get("/home/...")

+2

Das ist das Gegenteil von dem, was ich suche. Du nimmst einen "Pfad" und bekommst einen 'FileStore', aber ich möchte einen' FileStore' nehmen und einen 'Pfad' bekommen. – Jeffrey