java - 如何导航到 JFileChooser 中的网络主机?

标签 java windows filesystems jfilechooser smb

问题

我有一个 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 .
我自己尝试开发一个文件包装器,它充当 FileSmbFile 类的混合体。但我放弃了,因为它给我带来了噩梦。
然后我有了写一个简单的 Dialog 的想法,列出以前用 jcifs 扫描的网络共享,让用户选择其中一个。然后应该显示一个带有所选共享的 jFileChooser

当我实现这个想法时,整个问题的 super 简单解决方案让我感到震惊。

由于指向 \\ComputerName\ShareName 并单击 更高一级 按钮绝对没有问题,因此必须可以重现此步骤。它是。实际上,在查看 jFileChooser 的底层时,我了解到像 MyComputerNetwork 这样的地方是 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/

相关文章:

java - 无法在子类中解析泛型类型变量

windows - obj文件夹上的Visual Studio 2017 Xamarin Build访问被拒绝

c# - 需要从空格分隔的字符串中的特定位置删除特定引号,同时保留其他引号

mysql - MySQL 使用什么文件系统?

java - 嵌入式与非嵌入式 Java 服务器

java - Java中的服务器客户端聊天室

java - Apache Spark 网络端口配置

c++ - 在 C++ 中的 sleep 期间忽略键盘输入?

android - 检查给定文件是否存在于此路径上或 Android 文件系统中是否存在?

macos - DropBox Mac 客户端如何工作?