2012-05-21 16 views
10

Sto provando a trovare un modo per rilevare quando un'unità flash è stata collegata al mio computer. Finora, la soluzione che ho trovato è stato il sondaggio FileSystem#getFileStores per le modifiche. Questo in effetti mi dice quando l'unità flash è stata inserita, ma per quanto posso dire non c'è modo di recuperare il percorso per esso. FileStore#type e FileStore#name sembrano entrambi altamente inaffidabili in quanto il loro valore di ritorno è specifico dell'implementazione, ma sembrano essere gli unici metodi che potrebbero restituire qualsiasi informazione rilevante che potrebbe aiutare a trovare la directory per il FileStore.Trova la directory per un FileStore

Con questo in mente, il seguente codice:

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(); 
     } 
    } 
} 

mi ha dato questo output:

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

/* snip */ 

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

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

Come si è visto, FileStore#type restituisce il formato del disco e FileStore#name restituisce la posizione di il file del dispositivo per l'unità. Per quanto ne so, l'unico metodo che ha la posizione dell'unità è il metodo toString, ma estrarre il nome del percorso da esso sembra pericoloso perché non sono sicuro di quanto bene quella particolare soluzione reggerebbe su altri sistemi operativi e versioni future di Java.

C'è qualcosa che mi manca qui o semplicemente non è possibile con Java?

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 

risposta

10

Ecco un lavoro temporaneo in giro fino a trovare una soluzione migliore:

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; 
} 

Per quanto ne so, questa soluzione funziona solo per i sistemi Windows e Linux.

Devi prendere il IOException nel ciclo di Windows perché se non c'è CD nell'unità CD viene generata un'eccezione quando si tenta di recuperare il FileStore per esso. Questo potrebbe accadere prima di iterare su ogni root.

+0

Funziona davvero per Windows? Sembra che mancherebbe un disco che monto su C: \ Data. Il punto che sto usando questa nuova API è che mi ha promesso di trovarmi tutti i punti di mount e non solo le radici. – Trejkaz

+0

Inoltre,/media? Non intendi/mnt? – Trejkaz

+0

@Trejkaz Non sapevo che potessi farlo. Funziona per il caso standard in cui le unità sono montate come lettere. Almeno su Ubuntu, le cose sono montate di default su/media. Si potrebbe anche usare/etc/mtab per un lavoro più flessibile sui sistemi Linux (non uso molto Windows così tanto, quindi non ne conosco un altro). – Jeffrey

0

Non ho davvero esplorato questa zona di Java, ma ho trovato this, che sembra essere correlato. Utilizza File.listRoots()

Sembra esserci anche un numero di domande correlate collegate anche lì.

+1

'File.listRoots' funziona solo per Windows, e ho rivisto quelle domande senza alcun risultato.Sono stati tutti invitati prima che nio2 venisse fuori – Jeffrey

+0

Ahh> _> Continuerò a cercare e modificare questa risposta se trovo qualcosa –

+0

@Jeffrey non funzionerà nemmeno per Windows perché su Windows, puoi avere unità non montate su un'unità lettera. – Trejkaz

4

Questo è quello che ho finito per fare. Questo è limitato a Windows + UNIX ma evita di utilizzare strumenti esterni o chiamate di libreria aggiuntive. Ruba le informazioni che Java ha già negli oggetti FileStore

LinuxFileStore estende definitivamente UnixFileStore, quindi funzionerà. Stesso accordo per Solaris. Poiché Mac OS X è UNIX, probabilmente funziona lì, ma non sono sicuro perché non ho potuto vedere la sua sottoclasse in qualsiasi posto stavo cercando.

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

Nota per altri: Poiché i campi privati ​​sono soggetti a modifiche senza preavviso, questo funzionerà solo per la versione corrente di Java fino a quando non verrà confermato diversamente. – Jeffrey

+1

Sì. Aggiungere decisamente test unitari per rilevare il comportamento che cambia, se si utilizza questo. – Trejkaz

-1

uso più semplice modo Files.getFileStore(Paths.get("/home/...")

+2

Questo è l'inverso di quello che sto cercando. Stai prendendo un 'Path' e ottieni un' FileStore', ma voglio prendere un 'FileStore' e ottenere un' Percorso'. – Jeffrey

Problemi correlati