为了确认问题,我单独建了一个测试项目,写了一个测试类,分别在Java1.4.2、Java5、Java6下运行, 结果确实让我惊讶:
- public class URLTest {
- public static void main(String[] args) {
- URL url1 = URLTest.class.getResource("te st.txt");
- URL url2 = URLTest.class.getResource("中文.txt");
- System.out.println("te st.txt => " + url1.getFile() + ", exist => " + new File(url1.getFile()).exists());
- System.out.println("中文.txt => " + url2.getFile() + ", exist => " + new File(url2.getFile()).exists());
- }
- }
其中“te st.txt”和"中文.txt"是和测试类放在一起的测试文件。
Java1.4.2下输出:
- te st.txt => /E:/CODE/Test/bin/url/te st.txt, exist => true
- 中文.txt => /E:/CODE/Test/bin/url/中文.txt, exist => true
Java5和Java6均输出:
- te st.txt => /E:/CODE/Test/bin/url/te%20st.txt, exist => false
- 中文.txt => /E:/CODE/Test/bin/url/%e4%b8%ad%e6%96%87.txt, exist => false
看来,原来URL.getFile()是在1.4.2下能自动解码的,到了老虎和野马那里却不灵了,从而导致找不到资源文件。找到了问题,我长舒了一口气。
既然问题已经找到,答案呼之欲出,不过,为什么Java5以后要修改URL的行为,不再自动解码呢?我还是有些疑惑。
接下来,我一不做二不休,不就是类路径么,我再改,把编译路径从“bin”改成“bin all”,中间加空格,再次运行。。。。。。
Java1.4.2下输出:
- te st.txt => /E:/CODE/Test/bin%20all/url/te st.txt, exist => false
- 中文.txt => /E:/CODE/Test/bin%20all/url/中文.txt, exist => false
Java5和Java6均输出:
- te st.txt => /E:/CODE/Test/bin%20all/url/te%20st.txt, exist => false
- 中文.txt => /E:/CODE/Test/bin%20all/url/%e4%b8%ad%e6%96%87.txt, exist => false
哈哈,Java1.4.2的URL终于露馅了,原来它的解码是不完全的!原来URL.getFile()本身就是陷阱啊!即使是在1.4.2下,它也只是给我们一个迷惑的假相。
回头想想,为什么Sun要冒着版本不兼容的危险,也要修改URL的行为呢?这或许就是其深层次的原因。
[解难]
搞清楚了问题的症结,按方抓药即可。URLDecoder正是用来干这个活的,同时祭出Google,看看同志们是不是早就搞定这个问题了,放眼望去,URL.getFile()搜出来的结果还真不少啊,连带上URL.getPath()也受到牵连,而且URL.getFile()和URL.getPath()得到的路径还可能不一致!又是一个陷阱啊。
终解,用URLDecoder:
- System.out.println("te st.txt =decode=> " + URLDecoder.decode(url1.getFile(), "UTF-8"));
- System.out.println("中文.txt =decode=> " + URLDecoder.decode(url2.getFile(), "UTF-8"));
另外,URI也是可以自动解码的:
- System.out.println("te st.txt =uri=> " + new URI(url1.getFile()).getPath());
- System.out.println("te st.txt =uri=> " + new URI(url2.getFile()).getPath());
在Java5和Java6下运行,二者皆输出正常:
- te st.txt => /E:/CODE/Test/bin%20all/url/te%20st.txt, exist => false
- 中文.txt => /E:/CODE/Test/bin%20all/url/%e4%b8%ad%e6%96%87.txt, exist => false
- te st.txt =decode=> /E:/CODE/Test/bin all/url/te st.txt
- 中文.txt =decode=> /E:/CODE/Test/bin all/url/中文.txt
- te st.txt =uri=> /E:/CODE/Test/bin all/url/te st.txt
- te st.txt =uri=> /E:/CODE/Test/bin all/url/中文.txt
不过,1.4.2下,URI又可能是一个陷阱:
- te st.txt => /E:/CODE/Test/bin/url/te st.txt, exist => true
- 中文.txt => /E:/CODE/Test/bin/url/中文.txt, exist => true
- te st.txt =decode=> /E:/CODE/Test/bin/url/te st.txt
- 中文.txt =decode=> /E:/CODE/Test/bin/url/中文.txt
- java.net.URISyntaxException: Illegal character in path at index 24: /E:/CODE/Test/bin/url/te st.txt
- at java.net.URI$Parser.fail(URI.java:2752)
- at java.net.URI$Parser.checkChars(URI.java:2925)
- at java.net.URI$Parser.parseHierarchical(URI.java:3009)
- at java.net.URI$Parser.parse(URI.java:2967)
- at java.net.URI.<init>(URI.java:574)
- at url.URLTest.main(URLTest.java:24)
- Exception in thread "main"
URI对于不完整解码的路径,会抛语法异常。