我们软件的用户需要在Java swing应用程序中浏览Windows 10上的网络共享,但是swing的JFileChooser默认情况下不具有此功能。
在此相关文章中 How to navigate to a network host in JFileChooser? 提出了使用ShellFolder(sun私有API)设置JFileChooser的当前目录的不错的解决方案,并且在过去的几年中我们一直在使用这种方法进行一些修改,而没有任何问题。
public static File getNetworkShareFolder( final File folder ) throws IllegalArgumentException {
final File file = new NonCanonicalizingFile( folder.getPath() );
if( isNetworkShareFolder( file ) ) { // assume Win32ShellFolderManager2 will be present
try {
// JRE-13272 -PRIVATE API that must eventually be swapped for Java 9 alternative
// Using reflection because Win32ShellFolderManager2 may not exist in rt.jar on Linux build server
final Class win32ShellMgr = Class.forName( "sun.awt.shell.Win32ShellFolderManager2" );
// get static creation method from class, execute it
final Method cfMethod = win32ShellMgr.getMethod( "createShellFolder", File.class );
return (ShellFolder) cfMethod.invoke( win32ShellMgr.newInstance(), file );
} catch( final Exception xx ) {
xx.printStackTrace();
}
}
throw new IllegalArgumentException( "Given path is not a Windows network share folder." );
}
但是,我们正在迁移到Java 11,在Java 9以及更高版本中,私有API被封装了,并且我们被授权不再使用它们。不用担心,OpenJDK中的替换API已放入Swing filechooser的子程序包中的FileSystemView中。
sun.awt.shell.ShellFolder.isComputerNode(File)-> javax.swing.filechooser.FileSystemView.getFileSystemView()。isComputerNode(File)sun.awt.shell.ShellFolder.getShellFolder(File)-> javax.swing .filechooser.FileSystemView.getFileSystemView()。getLinkLocation(File)
所以以前的代码现在变成了
public static File getNetworkShareFolder( final File folder ) throws IllegalArgumentException {
final File file = new NonCanonicalizingFile( folder.getPath() );
if( isNetworkShareFolder( file ) ) {
try {
return FileSystemView.getFileSystemView().getLinkLocation( file );
} catch( final Exception xx ) {
xx.printStackTrace();
}
}
throw new IllegalArgumentException( "Given path is not a Windows network share folder." );
}
public static boolean isNetworkShareFolder( final File folder ) {
return FileSystemView.getFileSystemView().isComputerNode( new NonCanonicalizingFile( folder.getPath() ) );
}
这很好,但不幸的是,getShellFolder()和getLinkLocation()都在Java 11下抛出了一个Java 8下没有抛出的异常。
java.nio.file.InvalidPathException:UNC路径缺少共享名: \ 100.212.51.37为 java.base / sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:118) 在 java.base / sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:77) 在java.base / sun.nio.fs.WindowsPath.parse(WindowsPath.java:92)在 java.base / sun.nio.fs.WindowsFileSystem.getPath(WindowsFileSystem.java:229) 在java.base / java.nio.file.Path.of(Path.java:147)在 java.base / java.nio.file.Paths.get(Paths.java:69)位于 java.desktop / sun.awt.shell.ShellFolder.getShellFolder(ShellFolder.java:247) 在 java.desktop / javax.swing.filechooser.FileSystemView.getLinkLocation(FileSystemView.java:641)
现在看来,除非它具有实际的共享名称,否则现在认为UNC路径无效,即“ \\ 100.212.51.37 \”无效,但“ \\ 100.212.51.37 \ myShare”是可以的。
现在,如果您获得UNC路径“ \\ 100.212.51.37 \ myShare”的外壳程序文件夹,然后再获取getParent(),则首先获得我们想要的“ \\ 100.212.51.37 \”的外壳程序文件夹。不幸的是,由于鸡和鸡蛋的问题,这种解决方法对我们的客户不可行-用户通常还不知道任何实际的共享名称,这是他们首先要浏览的名称!
Argh-在Java 8下效果很好,但是在Java 11中,即使您使用以下方法破坏了封装以使用原始的ShellFolder私有API,
'--add-exports', 'java.desktop/sun.awt.shell=ALL-UNNAMED'
这无济于事,因为先前的解决方案现在在Java 11(9+)下引发了相同的Exception。
我们在StackOverflow上看到的另一种解决方案是使用JCIFS中的SmbFile类,但是由于安全限制,我们很难使用第三方代码。尤其是如果未针对Java 11 JPMS对其进行更新且不使用私有API。
有趣的是,JavaFX中的DirectoryChooser没有此问题。如果用户手动键入网络主机,它将很乐意显示该主机的所有共享名。如果需要的话,我们会采用这种方式,但是在Swing应用程序的FX Stage之间处理模态很丑陋,并且可能需要进行大量工作。
仍然希望有一个更简单的解决方法,使JFileChooser在Java 11(Java 9+)中显示网络共享!也许有人知道FX DirectoryChooser正在使用的技巧,并且可以将其应用于JFileChooser?
答案 0 :(得分:0)
仍在寻找更好的解决方案,但与此同时,由于网络共享,我们决定用Java 11中的JavaFX的DirectoryChooser替换JFileChooser。 DirectoryChooser非常乐意允许用户键入根网络共享,它将显示所有网络共享名称。正在启动DirectoryChooser的UI仍然是摇摆UI,但是至少在Windows 10下,我们没有遇到模式或焦点问题。
但是,除了必须仔细管理JavaFX Platform.runLater()和SwingUtilities.invokeLater()之间的线程之外,我们还有很多弊端
1)DirectoryChooser不允许多项选择。 JFileChooser可以。
2)DirectoryChooser仅允许选择目录,而不是文件。 耸肩谁需要允许选择目录或文件?愚蠢。只有这正是我们的客户在多个实例中需要做的事情。 JFileChooser支持此功能。
3)DirectoryChooser不允许输入无效路径。 ??是的,事实上,我们的一位客户有一个特定的要求,即输入一条尚不存在的路径(预配置),但必须在任务驱动器插入网络后输入。 JFileChooser允许这样做,并且可以非常方便地导航到所需的根目录,然后只需键入路径的最后一部分(目录或共享名)。
4)DirectoryChooser与应用程序样式不匹配。在JavaFX中,您可以在Scene的根节点上设置自己的CSS,但不能在DirectoryChooser上设置。看来DirectoryChooser实际上是在调用本机文件选择器,它应该使用系统颜色方案。不幸的是,对于我们的飞行员在夜间使用“暗模式”进行操作时,Windows 10 File Explorer直到1809版才开始遵循“暗模式”设置,而我们的客户几乎都没有。