为什么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个选择:

  1. fn上运行URLEncoder#encode()两次(注意: encode() ,而不是encoder() )。
  2. 请改用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());