问题
我有一个 JFileChooser,我需要以编程方式将其 currentDirectory 设置为包含多个 SMB 共享的网络主机(例如 \\blah
)。从技术上讲,这不是“目录”,而是代表可用共享列表的 shell 文件夹。
JFileChooser 可以毫无问题地导航到特定的共享(例如
\\blah\someShare
)但不能处理主机“目录”本身(例如\\blah
).用户可以通过“网络”shell 文件夹导航到 JFileChooser 中的此类“目录”,或者通过查找特定共享并导航到其父目录。调试显示该目录在后台表示为
Win32ShellFolder2
。到目前为止,我所有以编程方式设置 currentDirectory 的尝试都失败了。new File("\\\\blah")
可以创建,但从 Java 的角度来看实际上并不存在。
失败的解决方案尝试
chooser.setCurrentDirectory(new File("\\\\blah"));
失败,因为
JFileChooser
检查给定目录是否存在,并且new File("\\\\blah").exists()
返回 false。File dir = new File("\\\\blah").getCanonicalFile();
异常失败:
java.io.IOException: Invalid argument at java.io.WinNTFileSystem.canonicalize0(Native Method) at java.io.WinNTFileSystem.canonicalize(WinNTFileSystem.java:428) at java.io.File.getCanonicalPath(File.java:618) at java.io.File.getCanonicalFile(File.java:643)
File dir = ShellFolder.getShellFolder(new File("\\\\blah"));
异常失败:
java.io.FileNotFoundException at sun.awt.shell.ShellFolder.getShellFolder(ShellFolder.java:247)
File dir = new Win32ShellFolderManager2().createShellFolder(new File("\\\\blah"));
异常失败:
java.io.FileNotFoundException: File \\blah not found at sun.awt.shell.Win32ShellFolderManager2.createShellFolder(Win32ShellFolderManager2.java:80) at sun.awt.shell.Win32ShellFolderManager2.createShellFolder(Win32ShellFolderManager2.java:64)
路径 dir = Paths.get("\\\\blah");
异常失败:
java.nio.file.InvalidPathException: UNC path is missing sharename: \\blah at sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:118) at sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:77) at sun.nio.fs.WindowsPath.parse(WindowsPath.java:94) at sun.nio.fs.WindowsFileSystem.getPath(WindowsFileSystem.java:255) at java.nio.file.Paths.get(Paths.java:84)
最佳答案
曾几何时,我遇到过这样的任务,我可以说这真的很烦人。一开始听起来很容易,但是当你开始挖掘和尝试时,越来越多的问题出现了。我想谈谈我的旅程。
据我了解,这里的问题是 \\ComputerName\
不是文件系统中的真实位置。它是一个抽象层,其内容取决于您的身份验证凭据。而且它仅适用于 Windows 机器,因此去那里会破坏 Java 的系统独立性法则。总结一下,File
对象无法指向任何东西。
您可以使用 Samba 库 jcifs但在它们的实现中,类 SmbFile
需要用户身份验证,并且与 java File
类不兼容。所以你不能将它与 jFileChooser
一起使用。可悲的是,他们对更改它不感兴趣,您可以阅读 here .
我自己尝试开发一个文件包装器,它充当 File
和 SmbFile
类的混合体。但我放弃了,因为它给我带来了噩梦。
然后我有了写一个简单的 Dialog 的想法,列出以前用 jcifs
扫描的网络共享,让用户选择其中一个。然后应该显示一个带有所选共享的 jFileChooser
。
当我实现这个想法时,整个问题的 super 简单解决方案让我感到震惊。
由于指向 \\ComputerName\ShareName
并单击 更高一级
按钮绝对没有问题,因此必须可以重现此步骤。它是。实际上,在查看 jFileChooser
的底层时,我了解到像 MyComputer
或 Network
这样的地方是 ShellFolders
,它们是特殊情况File
对象。但是这些 Shell 文件夹是 protected ,不是 Java API 的一部分。
所以我不能直接实例化这些。但是我可以访问 FileSystemView
来处理文件系统上的系统相关 View ,例如为特殊位置创建这些 Shell 文件夹。
这么长的文字简短的回答。如果您知道一个共享名,请为该共享名创建一个文件。然后使用 FileSystemView
获取其父文件。瞧,你可以使用生成的 File
对象,它扩展了一个 ShellFolder
jFileChooser
.
File f = new File("\\\\ComputerName\\ShareFolder");
FileSystemView fsv = FileSystemView.getFileSystemView();
f = fsv.getParentDirectory(f);
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(f);
最后一点:此解决方案不会要求您提供登录信息。因此,必须先在 Windows 中访问这些共享,然后才能在此处使用它们。
编辑:抱歉文本太长。除夕夜,我喝醉了。现在我想补充一点,我发现了相反的情况。
FileSystemView fsv = FileSystemView.getFileSystemView();
File Desktop = fsv.getRoots()[0];
在 Windows 系统上,这应该会为您提供桌面文件夹。如果您在此处列出所有文件:
for(File file : Desktop.listFiles())
System.out.println(file.getName());
您会注意到一些具有奇怪名称的条目:
::{20D04FE0-3AEA-1069-A2D8-08002B30309D} // My Computer
::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C} // Network
::{031E4825-7B94-4DC3-B131-E946B44C8DD5} // User Directory
我不知道这些代码是否适用于所有 Windows 版本,但它们似乎适用于 Windows7。因此,您可以使用它来获取 Network Shell 文件夹,然后获取具有共享的计算机。
File Network = fsv.getChild(Desktop, "::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}");
File Host = fsv.getChild(Network, "COMPUTERNAME"); // Must be in Capital Letters
这里的问题是这将花费大约 10 秒,因为会扫描网络文件夹中的内容。
关于java - 如何导航到 JFileChooser 中的网络主机?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33640908/