我有一个使用JFileChooser选择目录的应用程序。在这个应用程序中,我不想尝试处理符号链接,我想在多个平台上运行。因此,代码尝试确定所选文件是否为符号链接,如果是,则显示错误对话框。
以下是从JFileChooser获取文件的代码。
public File getDirectoryChoice(String buttonText, String currentDirectory)
{
File chosenFile = null;
if (fileChooser == null) { fileChooser = new JFileChooser(); }
if (currentDirectory != null)
{ fileChooser.setCurrentDirectory(new File(currentDirectory)); }
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fileChooser.setApproveButtonText(buttonText);
int returnValue = fileChooser.showOpenDialog(mainFrame);
if (returnValue == JFileChooser.APPROVE_OPTION)
{
chosenFile = fileChooser.getSelectedFile();
}
return chosenFile;
}
以下是我用来确定所选文件是否为符号链接的代码:
public static boolean isSymbolic(File f)
{
try
{
String absolute = f.getAbsolutePath();
String canonical = f.getCanonicalPath();
return !(absolute.equals(canonical));
}
catch (IOException ioe)
{
return false;
}
}
在Windows 7上:如果用户使用鼠标选择给定目录,则可以正常工作。如果用户在文件名文本框中键入相同的目录名,则第二个代码段表示绝对路径和规范路径不相同。用户是否输入尾随反斜杠并不重要。
当我在'return'语句行的调试器中停止并查看两个字符串的详细信息时,绝对路径字符串的哈希值是一个很大的负数,而规范字符串的哈希值是0.我不知道为什么会这样,并且实际上想知道它是否是(eclipse)调试器的怪癖。
有谁能告诉我为什么会出现这种差异?
答案 0 :(得分:2)
仔细检查您输入的字符串与
我试了一下,不假思索地键入了c:\temp
。就像在测试中一样,isSymbolic()
方法返回true
。但仔细观察后,我注意到当我在文件选择器中选择此路径时,它返回了C:\temp
(注意大写C
)。
所以即使它很难看,你也可以添加一个像这样的特殊情况:
if (System.getProperty("os.name").toLowerCase().indexOf("win") >= 0)
return !(absolute.equalsIgnoreCase(canonical));
else
return !(absolute.equals(canonical));
您还可以查看以下相关问题:“Java 1.6 - determine symbolic links”。那里有很多答案你可能会觉得有帮助。
答案 1 :(得分:1)
如果您将absolute.hashCode()
和canonical.hashCode()
添加到Eclipe的“表达式”窗口中,您应该会看到正确的值 - 两者都不为零。 String具有初始化为0的hash
成员。然后在执行hashCode()
时将其更新为正确的值。
所以你可能看到的是absolute
字符串的计算哈希值,还没有canonical
字符串的计算哈希值。
在String.hashCode()
中放置一个断点,您将在Windows上看到getCanonicalPath()
触发absolute.hashCode()
。似乎在Windows上实现getCanonicalPath()
缓存了规范化的结果。介于WinNTFileSystem.canonicalize()
之间的某个位置,缓存结果映射中的查找会触发absolute.hashCode()
。
因此,在return
isSymbolic()
语句中设置的断点处,absolute
有一个有效的哈希码,而canonical
仍然为零。
以下是显示absolute.hashCode()
执行f.getCanonicalPath()
执行的堆栈跟踪:
String.hashCode() line: 1482 [local variables unavailable]
ExpiringCache$1(HashMap<K,V>).getEntry(Object) line: 344
ExpiringCache$1(LinkedHashMap<K,V>).get(Object) line: 280
ExpiringCache.entryFor(String) line: 83
ExpiringCache.get(String) line: 58
WinNTFileSystem(Win32FileSystem).canonicalize(String) line: 377
File.getCanonicalPath() line: 559
Test.isSymbolic(File) line: 25
Test.main(String[]) line: 16