Java 11 上 ShellFolder.getShellFolder() 的替换或使用方式
Replacement or way of using ShellFolder.getShellFolder() on Java 11
我目前正在使用 ShellFolder.getShellFolder() 来确定特定路径是否在本地驱动器上(直接连接到 Windows 机器)或远程驱动器。
package com.jthink.songkong.analyse.analyser;
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 Windows NTFS or FAT32
*
* @param newPath
* @return
*/
public static boolean isNTFSOrFAT32(String newPath)
{
Path root = Paths.get(newPath).getRoot();
if (root == null)
{
return false;
}
try
{
FileStore fs = Files.getFileStore(root);
if (fs.type().equals(WindowsFileSystem.NTFS)
|| fs.type().equals(WindowsFileSystem.FAT)
|| fs.type().equals(WindowsFileSystem.FAT32)
|| fs.type().equals(WindowsFileSystem.EX_FAT))
{
return true;
}
return false;
}
catch (IOException ex)
{
MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
return false;
}
}
/**
* Is this a remote drive, only works for Windows because relies on underlying Windows code
*
* @param newPath
*
* @return true if this a remote (Network) drive
*/
public static boolean isRemote(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.NETWORK_DRIVE))
{
return true;
}
else if (cols[i].getTitle().equals(WINDOWS_SHELL_ATTRIBUTES)
&& ((String) shellFolder.getFolderColumnValue(i)).startsWith("\"))
{
return true;
}
}
}
catch (Exception ex)
{
return false;
}
return false;
}
/**
* Is this a local drive, only works for Windows 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)
&& ((String) shellFolder.getFolderColumnValue(i)).startsWith("\"))
{
return false;
}
}
}
catch (Exception ex)
{
return true;
}
return true;
}
}
这在 Java 8
上工作正常
我现在转到 Java 11,我正在使用 maven 编译项目,如果我从 增加编译器的 source 参数8至9(或以上)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<encoding>UTF-8</encoding>
<compilerVersion>11</compilerVersion>
<source>8</source>
<target>11</target>
<verbose>true</verbose>
<fork>true</fork>
</configuration>
</plugin>
由于模块系统的引入导致编译失败(保持8,目标11可以)
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] c:\Code\jthink\SongKong\src\main\java\com\jthink\songkong\analyse\analyser\WindowsFilesystemType.java:[5,14] error: package sun.awt.shell is not visible
(package sun.awt.shell is declared in module java.desktop, which does not export it)
[ERROR] c:\Code\jthink\SongKong\src\main\java\com\jthink\songkong\analyse\analyser\WindowsFilesystemType.java:[6,14] error: package sun.awt.shell is not visible
(package sun.awt.shell is declared in module java.desktop, which does not export it)
[INFO] 2 errors
所以我正在寻找替代方法,或者:
- 有没有办法将 src 设置为 11 并允许使用某些模块选项进行编译
- 最好我可以使用标准 java 库
可靠地检测本地或远程驱动器
我需要 isLocal() 的原因是我的程序重命名文件,用户可以选择将路径长度限制为 259 个字符,因为更长的长度会给 Windows Explorer 带来问题,但如果它们是修改远程驱动器通常不会强制执行此要求,我将向问题添加更多详细信息。
例如,如果音乐文件在本地驱动器上供 Windows 使用,则应用程序会重命名音乐文件,然后他们可能希望强制执行该限制。但如果它是一个网络驱动器,他们可能不会,因为文件经常存储在 Nas 上,他们只能通过 Windows 访问文件,因为我的应用程序可以 运行 on Windows 但是不在 Nas 上。
目前似乎没有替代我在标准 Java API 中所需的功能(在 Windows 上识别路径是远程路径还是本地路径).
因此,选择是继续使用将来可能不会出现的非 public class 还是编写 hacky 代码与操作系统命令交互 (net
)将来可能会改变。
所以务实的解决办法是我继续使用非publicclass,希望能给publicapi加点东西,如果它不是并且非 public class 被删除然后我将不得不编写代码来与网络对话。
为了允许在编译时使用 Maven 访问这个非public class,我将以下内容添加到编译器插件
<compilerArgs>
<arg>--add-exports=java.desktop/sun.awt.shell=ALL-UNNAMED</arg>
</compilerArgs>
例如
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<encoding>UTF-8</encoding>
<compilerVersion>11</compilerVersion>
<source>11</source>
<target>11</target>
<verbose>true</verbose>
<fork>true</fork>
<compilerArgs>
<arg>--add-exports=java.desktop/sun.awt.shell=ALL-UNNAMED</arg>
</compilerArgs>
</configuration>
</plugin>
不幸的是,这个解决方案失败了 java 17 开始我看着太阳 shell classes 看看我是否可以复制它们,sun.awt.shell 没问题,但是 windows 实现依赖于非 java 库
static {
// Load library here
sun.awt.windows.WToolkit.loadLibraries();
}
所以这是个问题。
在下面创建了一些东西,但仅靠猜测是不可靠的
public class WindowsFilesystemType
{
public static final String WINDOWS_SHELL_ATTRIBUTES = "Attributes";
public static final String WINDOWS_SHELL_SIZE = "Size";
/**
* Is Windows NTFS or FAT32
*
* @param newPath
* @return
*/
public static boolean isNTFSOrFAT32(String newPath)
{
Path root = Paths.get(newPath).getRoot();
if (root == null)
{
return false;
}
try
{
FileStore fs = Files.getFileStore(root);
if (fs.type().equals(WindowsFileSystem.NTFS)
|| fs.type().equals(WindowsFileSystem.FAT)
|| fs.type().equals(WindowsFileSystem.FAT32)
|| fs.type().equals(WindowsFileSystem.EX_FAT))
{
return true;
}
return false;
}
catch (IOException ex)
{
MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
return false;
}
}
/**
* Is this a local drive, only works for Windows machine
*
* TODO unreliable since moved to Java 17
*
* @param newPath
*
* @return true if this a local drive
*/
public static boolean isLocal(String newPath)
{
//If not a windows fs unlikely to be local drive
if(!isNTFSOrFAT32(newPath))
{
return false;
}
//Mapped \ must be network drive ?
Path root = Paths.get(newPath).getRoot();
if (root.toString().startsWith("\"))
{
return false;
}
//Low drive letter assume local
root = Paths.get(newPath).getRoot();
if (
(root.toString().equals("C:\"))||
(root.toString().equals("D:\"))||
(root.toString().equals("E:\"))||
(root.toString().equals("F:\"))
)
{
return true;
}
//Assume network then if higher drive letter
return false;
}
}
我目前正在使用 ShellFolder.getShellFolder() 来确定特定路径是否在本地驱动器上(直接连接到 Windows 机器)或远程驱动器。
package com.jthink.songkong.analyse.analyser;
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 Windows NTFS or FAT32
*
* @param newPath
* @return
*/
public static boolean isNTFSOrFAT32(String newPath)
{
Path root = Paths.get(newPath).getRoot();
if (root == null)
{
return false;
}
try
{
FileStore fs = Files.getFileStore(root);
if (fs.type().equals(WindowsFileSystem.NTFS)
|| fs.type().equals(WindowsFileSystem.FAT)
|| fs.type().equals(WindowsFileSystem.FAT32)
|| fs.type().equals(WindowsFileSystem.EX_FAT))
{
return true;
}
return false;
}
catch (IOException ex)
{
MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
return false;
}
}
/**
* Is this a remote drive, only works for Windows because relies on underlying Windows code
*
* @param newPath
*
* @return true if this a remote (Network) drive
*/
public static boolean isRemote(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.NETWORK_DRIVE))
{
return true;
}
else if (cols[i].getTitle().equals(WINDOWS_SHELL_ATTRIBUTES)
&& ((String) shellFolder.getFolderColumnValue(i)).startsWith("\"))
{
return true;
}
}
}
catch (Exception ex)
{
return false;
}
return false;
}
/**
* Is this a local drive, only works for Windows 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)
&& ((String) shellFolder.getFolderColumnValue(i)).startsWith("\"))
{
return false;
}
}
}
catch (Exception ex)
{
return true;
}
return true;
}
}
这在 Java 8
上工作正常我现在转到 Java 11,我正在使用 maven 编译项目,如果我从 增加编译器的 source 参数8至9(或以上)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<encoding>UTF-8</encoding>
<compilerVersion>11</compilerVersion>
<source>8</source>
<target>11</target>
<verbose>true</verbose>
<fork>true</fork>
</configuration>
</plugin>
由于模块系统的引入导致编译失败(保持8,目标11可以)
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] c:\Code\jthink\SongKong\src\main\java\com\jthink\songkong\analyse\analyser\WindowsFilesystemType.java:[5,14] error: package sun.awt.shell is not visible
(package sun.awt.shell is declared in module java.desktop, which does not export it)
[ERROR] c:\Code\jthink\SongKong\src\main\java\com\jthink\songkong\analyse\analyser\WindowsFilesystemType.java:[6,14] error: package sun.awt.shell is not visible
(package sun.awt.shell is declared in module java.desktop, which does not export it)
[INFO] 2 errors
所以我正在寻找替代方法,或者:
- 有没有办法将 src 设置为 11 并允许使用某些模块选项进行编译
- 最好我可以使用标准 java 库 可靠地检测本地或远程驱动器
我需要 isLocal() 的原因是我的程序重命名文件,用户可以选择将路径长度限制为 259 个字符,因为更长的长度会给 Windows Explorer 带来问题,但如果它们是修改远程驱动器通常不会强制执行此要求,我将向问题添加更多详细信息。
例如,如果音乐文件在本地驱动器上供 Windows 使用,则应用程序会重命名音乐文件,然后他们可能希望强制执行该限制。但如果它是一个网络驱动器,他们可能不会,因为文件经常存储在 Nas 上,他们只能通过 Windows 访问文件,因为我的应用程序可以 运行 on Windows 但是不在 Nas 上。
目前似乎没有替代我在标准 Java API 中所需的功能(在 Windows 上识别路径是远程路径还是本地路径).
因此,选择是继续使用将来可能不会出现的非 public class 还是编写 hacky 代码与操作系统命令交互 (net
)将来可能会改变。
所以务实的解决办法是我继续使用非publicclass,希望能给publicapi加点东西,如果它不是并且非 public class 被删除然后我将不得不编写代码来与网络对话。
为了允许在编译时使用 Maven 访问这个非public class,我将以下内容添加到编译器插件
<compilerArgs>
<arg>--add-exports=java.desktop/sun.awt.shell=ALL-UNNAMED</arg>
</compilerArgs>
例如
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<encoding>UTF-8</encoding>
<compilerVersion>11</compilerVersion>
<source>11</source>
<target>11</target>
<verbose>true</verbose>
<fork>true</fork>
<compilerArgs>
<arg>--add-exports=java.desktop/sun.awt.shell=ALL-UNNAMED</arg>
</compilerArgs>
</configuration>
</plugin>
不幸的是,这个解决方案失败了 java 17 开始我看着太阳 shell classes 看看我是否可以复制它们,sun.awt.shell 没问题,但是 windows 实现依赖于非 java 库
static {
// Load library here
sun.awt.windows.WToolkit.loadLibraries();
}
所以这是个问题。
在下面创建了一些东西,但仅靠猜测是不可靠的
public class WindowsFilesystemType
{
public static final String WINDOWS_SHELL_ATTRIBUTES = "Attributes";
public static final String WINDOWS_SHELL_SIZE = "Size";
/**
* Is Windows NTFS or FAT32
*
* @param newPath
* @return
*/
public static boolean isNTFSOrFAT32(String newPath)
{
Path root = Paths.get(newPath).getRoot();
if (root == null)
{
return false;
}
try
{
FileStore fs = Files.getFileStore(root);
if (fs.type().equals(WindowsFileSystem.NTFS)
|| fs.type().equals(WindowsFileSystem.FAT)
|| fs.type().equals(WindowsFileSystem.FAT32)
|| fs.type().equals(WindowsFileSystem.EX_FAT))
{
return true;
}
return false;
}
catch (IOException ex)
{
MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
return false;
}
}
/**
* Is this a local drive, only works for Windows machine
*
* TODO unreliable since moved to Java 17
*
* @param newPath
*
* @return true if this a local drive
*/
public static boolean isLocal(String newPath)
{
//If not a windows fs unlikely to be local drive
if(!isNTFSOrFAT32(newPath))
{
return false;
}
//Mapped \ must be network drive ?
Path root = Paths.get(newPath).getRoot();
if (root.toString().startsWith("\"))
{
return false;
}
//Low drive letter assume local
root = Paths.get(newPath).getRoot();
if (
(root.toString().equals("C:\"))||
(root.toString().equals("D:\"))||
(root.toString().equals("E:\"))||
(root.toString().equals("F:\"))
)
{
return true;
}
//Assume network then if higher drive letter
return false;
}
}