为什么Java会自动解码URI编码文件名中的%2F?

时间:2010-05-04 13:41:46

标签: java file encoding uri

我有一个servlet需要写出具有用户可配置名称的文件。我正在尝试使用URI编码来正确转义特殊字符,但JRE似乎会自动将编码的正斜杠%2F转换为路径分隔符。

示例:

File   dir = new File("C:\Documents and Setting\username\temp");
String fn  = "Top 1/2.pdf";
URI    uri = new URI( dir.toURI().toASCIIString() + URLEncoder.encoder( fn, "ASCII" ).toString() );
File   out = new File( uri );

System.out.println( dir.toURI().toASCIIString() );
System.out.println( URLEncoder.encode( fn, "ASCII" ).toString() );
System.out.println( uri.toASCIIString() );
System.out.println( output.toURI().toASCIIString() );

输出结果为:

file:/C:/Documents%20and%20Settings/username/temp/
Top+1%2F2.pdf   
file:/C:/Documents%20and%20Settings/username/temp/Top+1%2F2.pdf
file:/C:/Documents%20and%20Settings/username/temp/Top+1/2.pdf

实例化新的File对象后,%2F序列会自动转换为正斜杠,最终路径不正确。有人知道解决这个问题的正确方法吗?

问题的核心似乎是那个

uri.equals( new File(uri).toURI() ) == FALSE

当URI中有%2F时。

我打算逐字使用URLEncoded字符串,而不是尝试使用File(uri)构造函数。

2 个答案:

答案 0 :(得分:5)

new File(URI)根据URI#getPath()获取的路径构建文件,而不是 - 您期望的那样 - URI#getRawPath()。这看起来像是“按设计”的特征。

您有两个选择:

  1. fn上运行URLEncoder#encode()两次(注意:encode(),而不是encoder())。
  2. 请改用new File(String)

答案 1 :(得分:2)

我认为@BalusC已经解决了代码中的直接问题。我只想指出其他一些问题

dir.toURI().toASCIIString()URLEncoder.encoder(fn, "UTF-8").toString()表达式确实做了不同的事情。

  • 第一个,将URI编码为字符串,根据URI语法应用URI编码规则。因此,例如,路径组件中的“/”将不会被编码,但查询或片段组件中的“/”将被编码为%2F。

  • 第二个,使用编码规则对fn字符串进行编码,而不参考字符串的内容。

File(URI)构造函数从文件URI到文件的映射是system dependent and undocumented。我有点惊讶它解码%2F,但它做了它的功能,而@BalusC解释了原因。外卖是使用明确依赖于系统的机制(“文件:”URI)可能存在问题。

最后,组合这些URI组件字符串是错误的。它应该是

URI uri = new URI(
        dir.toURI().toString() +
        URLEncoder.encoder(fn, "UTF-8").toString();

URI uri = new URI(
        dir.toURI().toASCIIString() +
        URLEncoder.encoder(fn, "ASCII").toString());