为什么Java会自动解码URI编码文件名中的%2F?
我有一个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)
构造函数。
new File(URI)
根据URI#getPath()
获取的路径构造文件,而不是URI#getRawPath()
。 这看起来像是“按设计”的特征。
你有2个选择:
- 在
fn
上运行URLEncoder#encode()
两次(注意:encode()
,而不是encoder()
)。 - 请改用
new File(String)
。
我认为@BalusC已经解决了代码中的直接问题。 我只想指出其他一些问题
dir.toURI().toASCIIString()
和URLEncoder.encoder(fn, "UTF-8").toString()
表达式实际上做了不同的事情。
-
第一个,将URI编码为字符串,根据URI语法应用URI编码规则。 因此,例如,路径组件中的“/”将不会被编码,但查询或片段组件中的“/”将被编码为%2F。
-
第二个,使用编码规则对
fn
String进行编码,而不引用字符串的内容。
File(URI)
构造函数从文件URI到文件的映射是系统相关的和未记录的 。 我有点惊讶它解码%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());