Найти каталог для FileStore

Я пытаюсь найти способ обнаружить, когда флеш-накопитель подключен к моему компьютеру. До сих пор решение, которое я нашел, состояло в опросе FileSystem#getFileStores изменений. Это действительно говорит мне, когда флэш-диск был вставлен, но насколько я могу судить, нет способа найти место для него. FileStore#type и FileStore#name обе кажутся крайне ненадежными, поскольку их возвращаемое значение является специфичным для реализации, но они появляются быть единственными методами, которые могут возвращать любую релевантную информацию, которая могла бы помочь найти каталог для FileStore.

Имея это в виду, следующий код:

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

Дал мне этот вывод:

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

/* snip */

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

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

Как оказалось, FileStore#type возвращает формат диска, а FileStore#name возвращает местоположение файла устройства для диска. Насколько я могу судить, единственным способом, который имеет расположение диска, является метод toString, но извлечение имени пути из него кажется опасным, потому что я не уверен, насколько хорошо это конкретное решение будет задерживаться на других операционных систем и будущих версий Java.

Есть ли что-то, что я здесь отсутствует, или это просто невозможно с использованием Java?

Информация о системе:

$ 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

Ответ 1

Здесь временная работа, пока не будет найдено лучшее решение:

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

Насколько я знаю, это решение будет работать только для систем Windows и Linux.

Вы должны поймать IOException в цикле Windows, потому что, если в CD-диске нет компакт-диска, возникает исключение, когда вы пытаетесь извлечь FileStore для него. Это может произойти до того, как вы перейдете к каждому корню.

Ответ 2

Это то, что я сделал. Это ограничивается Windows + UNIX, но избегает использования внешних инструментов или дополнительных вызовов библиотеки. Он крадет информацию, которую Java уже имеет в объектах FileStore

LinuxFileStore определенно расширяет UnixFileStore, поэтому он будет работать. Такая же сделка для Solaris. Поскольку Mac OS X является UNIX, он, вероятно, работает там, но я не уверен, потому что я не мог видеть его подкласс в любом месте, которое я искал.

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

Ответ 3

Я не изучал эту область java, но нашел этот, что, похоже, связано. Он использует File.listRoots()

Здесь также есть ряд связанных вопросов.

Ответ 4

Самый простой способ использования Files.getFileStore(Paths.get("/home/...")