当前位置: 首页 > 面试题库 >

如何在JFileChooser中导航到网络主机?

东郭淇
2023-03-14
问题内容

我有一个JFileChooser,我需要以编程方式将其currentDirectory设置为包含多个SMB共享(例如\\blah)的网络主机。从技术上讲,这不是“目录”,而是代表可用共享列表的shell文件夹。

  • JFileChooser导航到特定共享(例如\\blah\someShare)没有问题,但是不能处理主机“目录”本身(例如\\blah)。

  • 用户可以通过“网络”外壳文件夹,或找到特定的共享并导航至其父目录,来导航至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)
  • Path 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)

问题答案:

我找到了Windows特定的解决方案,该解决方案允许仅从名称(例如\\blah\\blah\)导航到任何可访问的计算机节点,而无需枚举Network
shell文件夹或给定节点上的网络共享的任何高级知识。

为计算机路径创建ShellFolder

在调试此问题时,我发现ShellFolder必须为给定的计算机路径创建一个才能导航到它。Win32ShellFolderManager2.createShellFolder()将调用File.getCanonicalPath()给定的文件,该文件又将调用WinNTFileSystem.canonicalize()。最后一次调用在计算机路径上始终失败。经过大量的实验,ShellFolder通过将File对象包装在绕过的东西中,我能够为任何可访问的计算机路径创建一个WinNTFileSystem.canonicalize()

/**
 * Create a shell folder for a given network path.
 *
 * @param path File to test for existence.
 * @return ShellFolder representing the given computer node.
 * @throws IllegalArgumentException given path is not a computer node.
 * @throws FileNotFoundException given path could not be found.
 */
public static ShellFolder getComputerNodeFolder(String path)
        throws FileNotFoundException {
    File file = new NonCanonicalizingFile(path);
    if (ShellFolder.isComputerNode(file)) {
        return new Win32ShellFolderManager2().createShellFolder(file);
    } else {
        throw new IllegalArgumentException("Given path is not a computer node.");
    }
}

private static final class NonCanonicalizingFile extends File {
    public NonCanonicalizingFile(String path) {
        super(path);
    }

    @Override
    public String getCanonicalPath() throws IOException {
        // Win32ShellFolderManager2.createShellFolder() will call getCanonicalPath() on this file.
        // Base implementation of getCanonicalPath() calls WinNTFileSystem.canonicalize() which fails on
        // computer nodes (e.g. "\\blah"). We skip the canonicalize call, which is safe at this point because we've
        // confirmed (in approveSelection()) that this file represents a computer node.
        return getAbsolutePath();
    }
}

诚然,此解决方案有两个边缘情况(例如可行,\\blah\\\blah\someShare\..\没有),理想情况下,OpenJDK应该在其末尾解决这些怪癖。这也是特定于操作系统和特定于实现的解决方案,在Windows上的OpenJDK安装程序之外无法使用。

与JFileChooser集成:选项1

与之集成的最简单方法JFileChooser是覆盖其approveSelection()方法。这样,用户可以在对话框中输入计算机路径(\\blah\\blah\),然后按Enter键导航到该位置。当给出了不存在或不可访问的路径时,将显示一条警报消息。

JFileChooser chooser = new JFileChooser() {
    @Override
    public void approveSelection() {
        File selectedFile = getSelectedFile();
        if (selectedFile != null && ShellFolder.isComputerNode(selectedFile)) {
            try {
                // Resolve path and try to navigate to it
                setCurrentDirectory(getComputerNodeFolder(selectedFile.getPath()));
            } catch (FileNotFoundException ex) {
                // Alert user if given computer node cannot be accessed
                JOptionPane.showMessageDialog(this, "Cannot access " + selectedFile.getPath());
            }
        } else {
            super.approveSelection();
        }
    }
};
chooser.showOpenDialog(null);

与JFileChooser集成:选项2

或者,FileSystemView可以通过覆盖其createFileObject(String)方法来检查计算机路径来增强此功能。这允许将计算机路径传递给JFileChooser(String,FileSystemView)构造函数,并且仍然允许用户导航到可访问的计算机路径。但是,仍然没有一种简单的方法可以在不覆盖的情况下向用户发送有关不可访问的计算机路径的消息JFileChooser.approveSelection()

public static class ComputerNodeFriendlyFileSystemView extends FileSystemView {

    private final FileSystemView delegate;

    public ComputerNodeFriendlyFileSystemView(FileSystemView delegate) {
        this.delegate = delegate;
    }

    @Override
    public File createFileObject(String path) {
        File placeholderFile = new File(path);
        if (ShellFolder.isComputerNode(placeholderFile)) {
            try {
                return getComputerNodeFolder(path);
            } catch (FileNotFoundException ex) {
                return placeholderFile;
            }
        } else {
            return delegate.createFileObject(path);
        }
    }

    // All code below simply delegates everything to the "delegate"

    @Override
    public File createNewFolder(File containingDir) throws IOException {
        return delegate.createNewFolder(containingDir);
    }

    @Override
    public boolean isRoot(File f) {
        return delegate.isRoot(f);
    }

    @Override
    public Boolean isTraversable(File f) {
        return delegate.isTraversable(f);
    }

    @Override
    public String getSystemDisplayName(File f) {
        return delegate.getSystemDisplayName(f);
    }

    @Override
    public String getSystemTypeDescription(File f) {
        return delegate.getSystemTypeDescription(f);
    }

    @Override
    public Icon getSystemIcon(File f) {
        return delegate.getSystemIcon(f);
    }

    @Override
    public boolean isParent(File folder, File file) {
        return delegate.isParent(folder, file);
    }

    @Override
    public File getChild(File parent, String fileName) {
        return delegate.getChild(parent, fileName);
    }

    @Override
    public boolean isFileSystem(File f) {
        return delegate.isFileSystem(f);
    }

    @Override
    public boolean isHiddenFile(File f) {
        return delegate.isHiddenFile(f);
    }

    @Override
    public boolean isFileSystemRoot(File dir) {
        return delegate.isFileSystemRoot(dir);
    }

    @Override
    public boolean isDrive(File dir) {
        return delegate.isDrive(dir);
    }

    @Override
    public boolean isFloppyDrive(File dir) {
        return delegate.isFloppyDrive(dir);
    }

    @Override
    public boolean isComputerNode(File dir) {
        return delegate.isComputerNode(dir);
    }

    @Override
    public File[] getRoots() {
        return delegate.getRoots();
    }

    @Override
    public File getHomeDirectory() {
        return delegate.getHomeDirectory();
    }

    @Override
    public File getDefaultDirectory() {
        return delegate.getDefaultDirectory();
    }

    @Override
    public File createFileObject(File dir, String filename) {
        return delegate.createFileObject(dir, filename);
    }

    @Override
    public File[] getFiles(File dir, boolean useFileHiding) {
        return delegate.getFiles(dir, useFileHiding);
    }

    @Override
    public File getParentDirectory(File dir) {
        return delegate.getParentDirectory(dir);
    }
}

用法:

ComputerNodeFriendlyFileSystemView fsv
    = new ComputerNodeFriendlyFileSystemView(FileSystemView.getFileSystemView());
JFileChooser chooser = new JFileChooser("\\\\blah", fsv);
chooser.showOpenDialog(null);


 类似资料:
  • 问题似乎是没有用新页面的内容更新元素。将问题行的替换为也不起作用。我做错了什么? 请注意,我必须能够对所有缩略图执行此操作(因此使用循环)。

  • 问题内容: 我有以下代码: 后者需要通过单击缩略图来导航以下HTML(当然是简化的),该缩略图指向一个新页面,然后需要单击该新页面中的链接: 但是我的代码吐出了以下错误: 问题似乎是该元素未使用新页面的内容进行更新。更换有问题的生产线的使用也不起作用。我究竟做错了什么? 请注意,我必须能够对所有缩略图执行此操作(因此需要循环)。 问题答案: 原来,您需要预先存储要导航的链接。这就是最终对我有用的东

  • 我正在构建包括两个容器的docker-comment服务。其中一个容器(节点)被设计成支持自动发现机制,并且需要成为主机局域网的一部分(因为我需要多播UDP包由局域网路由器处理,而不是内置的docker路由器)。 虽然docker-compose.yml中的network_mode:主机完美地做到了这一点,但我需要此服务也可以通过默认的docker-comment网络(如:超文本传输协议://节点

  • 问题内容: 我可以在源文件中设置书签,但是是否有快捷键可以导航到书签?在 导航 菜单中有一个goto线。但这没有用。 问题答案: 没有快捷键,但是您可以在“ 窗口” >“显示视图”>“其他…”_以及“ _常规” 类别内的对话框中显示一个“书签视图” ,然后双击所需的书签即可

  • 如何从React Router v4中的函数重定向到页面? 我可以从组件中找到很多关于导航的引用,在我的情况下,我需要从函数中导航

  • 曾几何时,采用滑动门创建的主导航比较流行,时至今日,滑动门慢慢退出历史舞台,简单平滑的水平主导航开始流行。这就是传说中的三十年河东,三十年河西。 本节,通过一个实例,来演示一下水平主导航的制作方法。首先,创建一个无序列表来包裹导航链接: <ul class = "mainnav">    <li><a href="#">文件</a></li>    <li><a href="#">编辑</a><