测试本地或远程路径(没有 sun.awt.shell.ShellFolder class)

Testing for local or remote path (without sun.awt.shell.ShellFolder class)

我正在尝试从 Java 15 移动到 Java 17 但是因为他们现在封装了内部结构并删除了标志 –illegal-access 我有一个问题。

来自https://www.baeldung.com/java-17-new-features

JEP 403 represents one more step toward strongly encapsulating JDK internals since it removes the flag –illegal-access. The platform will ignore the flag, and if the flag is present, the console will issue a message informing the discontinuation of the flag.

我有一个 class 失败,因为它引用了

sun.awt.shell.ShellFolder;
sun.awt.shell.ShellFolderColumnInfo;

class 的目的是在 Windows 系统上识别文件是否在本地文件系统上

import com.jthink.songkong.analyse.filename.WindowsFileSystem;
import com.jthink.songkong.ui.MainWindow;
import sun.awt.shell.ShellFolder;
import sun.awt.shell.ShellFolderColumnInfo;

import java.io.IOException;
import java.nio.file.FileStore;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Level;

/**
 * Only Windows can load these methods because of reliance on sun classes
 *
 */
public class WindowsFilesystemType
{

    public static final String WINDOWS_SHELL_ATTRIBUTES = "Attributes";
    public static final String WINDOWS_SHELL_ITEM_TYPE = "Item type";
    public static final String   WINDOWS_SHELL_SIZE = "Size";
    
    /**
     * Is this a local drive, only works for Windows machine because relies on underlying Windows code
     *
     * @param newPath
     *
     * @return true if this a local drive
     */
    public static boolean isLocal(String newPath)
    {
        try
        {
            Path root = Paths.get(newPath).getRoot();
            ShellFolder shellFolder = ShellFolder.getShellFolder(root.toFile());
            ShellFolderColumnInfo[] cols = shellFolder.getFolderColumns();
            for (int i = 0; i < cols.length; i++)
            {
                if (cols[i].getTitle().equals(WINDOWS_SHELL_SIZE)
                        &&  ((String) shellFolder.getFolderColumnValue(i)).startsWith(WindowsShellFileSystemType.LOCAL_DISK))
                {
                    return true;
                }
                else if (cols[i].getTitle().equals(WINDOWS_SHELL_ATTRIBUTES))
                {
                    //Mapped network drive
                    if(shellFolder.getFolderColumnValue(i)!=null && ((String)shellFolder.getFolderColumnValue(i)).startsWith("\"))
                    {
                        return false;
                    }
                    //SONGKONG-2186:Can be null if unmapped network drive
                    else if(shellFolder.getFolderColumnValue(i)==null)
                    {
                        return false;
                    }
                }
            }
        }
        catch (Exception ex)
        {
            MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
            return false;
        }
        return true;
    }

}

这可以通过其他方式实现吗,或者我仍然可以访问这些太阳 classes 吗?

我需要 isLocal() 的原因是我的程序重命名文件,用户可以选择将路径长度限制为 259 个字符,因为更长的长度会给 Windows Explorer 带来问题,但如果它们是修改远程驱动器通常不会强制执行此要求,我将向问题添加更多详细信息。

例如,应用程序重命名音乐文件,如果它们在本地驱动器上供 Windows 使用,那么他们可能想要强制执行该限制。但如果它是一个网络驱动器,他们可能不会,因为文件经常存储在 Nas 上,他们只能通过 Windows 访问文件,因为我的应用程序可以 运行 on Windows 但是不在 Nas 上。

请注意 ShellFolderFileSystemView API 的后端,它提供了在 UI 中显示文件信息的大部分功能。虽然没有提供测试文件是否在网络驱动器上的功能,但您的原始代码无论如何看起来更像是一种启发式方法。

到目前为止我发现的最简单的测试,仅基于 NIO,是针对卷序列号的,它仅适用于本地驱动器:

public class WindowsFilesystemType {
    public static boolean isNTFSOrFAT32(String newPath) {
        try {
            return switch(Files.getFileStore(Paths.get(newPath)).type()) {
                case "NTFS", "FAT", "FAT32", "EXFAT" -> true;
                default -> false;
            };
        } catch (IOException ex) {
            MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
            return false;
        }
    }

    public static boolean isRemote(String newPath) {
        try {
            FileStore fileStore = Files.getFileStore(Paths.get(newPath));
            return Integer.valueOf(0).equals(fileStore.getAttribute("volume:vsn"));
        } catch(Exception ex) {
            MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
            return false;
        }
    }

    public static boolean isLocal(String newPath) {
        try {
            FileStore fileStore = Files.getFileStore(Paths.get(newPath));
            return !Integer.valueOf(0).equals(fileStore.getAttribute("volume:vsn"));
        } catch(Exception ex) {
            MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
            return false;
        }
    }
}

此 Windows 文件存储属性尚未记录,但自 Java 7.

起有效