File.toURI不编码加号

时间:2017-10-09 10:30:31

标签: java file url uri

我只想在这里用这个问题检查自己的理智。我有一个文件名,其中包含+(加号)字符,在某些操作系统和文件系统(例如MacOS和HFS +)上完全有效。

但是,我发现我认为java.io.File#toURI()无法正常运行的问题。

例如:

new File("hello+world.txt").toURI().toString()

在我的Mac机器上返回:

file:/Users/aretter/code/rocksdb/hello+world.txt

然而,恕我直言,这是不正确的,因为文件名中的+(加号)字符尚未在URI中编码。 URI根本不代表原始文件名,URI中的+与文件名中的+字符具有非常不同的含义。

因此,如果我们解码URI,现在将用(空格)字符替换加号,并且我们丢失了信息。 e.g:

URLDecoder.decode(new File("hello+world.txt").toURI().toURL().toString)

结果是:

file:/Users/aretter/code/rocksdb/hello world.txt

我原本期望的是:

new File("hello+world.txt").toURI().toString()

导致:

file:/Users/aretter/code/rocksdb/hello%2Bworld.txt

因此,当以后使用和解码时,加号将被保留。

我很难相信Java SE中会出现这样一个明显的错误。有人可以指出我错在哪里吗?

另外,如果有解决方法,我想听听吗?请记住,我实际上并没有将静态字符串作为文件名提供给File,而是从磁盘读取文件目录,其中一些文件可能包含+(加号)字符。

5 个答案:

答案 0 :(得分:2)

让我试着澄清一下,

  • '+'plus字符用作编码字符,用于在HTML表单的上下文中编码''空格(a.k.a.application / x-www-form-urlencoded MIME格式)。
  • '%20'字符用作编码字符,用于在URL / URI格式的上下文中编码''空格。

'+'加上字符是威胁,作为URL上下文中的普通字符,并且不以任何形式编码(例如%20)。

因此,当您调用new File("hello+world.txt").toURI().toString()时,不对'+'字符执行任何编码(仅因为它不是必需的)。

现在来URLDecoderthis class是一个用于HTML表单解码的实用程序类。它将'+'加号视为编码字符,因此将其解码为''空格字符。在您的示例中,此类将URI作为正常的html表单字段的值(而不是URI值)处理为字符串值。永远不应该使用此类来解码完整的URI / URL值,因为它不是为此目的而设计的)

来自java docs of URLDecoder#decode(String)

  

解码x-www-form-urlencoded字符串。该平台的默认值   encoding用于确定any表示的字符   “%xy”形式的连续序列。

希望它有所帮助。

根据评论更新#1:

根据section 2.2,如果URI组件的数据与保留字符冲突,则冲突数据必须在形成URI之前进行百分比编码。

同样重要的是,URI的不同部分根据其上下文具有不同的保留字集。例如,/符号仅在URI的路径部分保留,+符号在查询字符串部分中保留。因此,无需在查询部分中转义/,同样无需在路径部分中转义+

在您的示例中,URI生成器File.toURI不对URI的路径部分中的+签名进行编码(因为+' is not considered as reserved word in path part) and you see the +'登录URI到字符串表示。

您可以参考URI recommendation了解更多详情。

相关答案:

  1. https://stackoverflow.com/a/1006074/1700467
  2. https://stackoverflow.com/a/2678602/1700467
  3. https://stackoverflow.com/a/4571518/1700467

答案 1 :(得分:1)

我假设您希望将文件名中的+符号编码为%2B。因此,当您将其解码时,您会将其作为+符号返回。

如果是这种情况,那么您需要使用URLEncoder.encode

System.out.println(URLEncoder.encode(new File("hello+world.txt").toURI().toString()));

它将对包括+符号在内的所有特殊字符进行编码。输出将是

file%3A%2Fhome%2FT8hvs7%2Fhello%2Bworld.txt

现在,解码使用URLDecoder.decode

System.out.println(URLDecoder.decode("file%3A%2Fhome%2FwQCXni%2Fhello%2Bworld.txt"));

将显示

file:/home/wQCXni/hello+world.txt

答案 2 :(得分:0)

显然这不是一个错误,documentation清楚地说

The plus sign "+" is converted into a space character " " .

你可以这样做:https://ideone.com/JHDkM4

import java.util.*;
import java.lang.*;
import java.io.*;
import static java.lang.System.out;


class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        out.println(new File("hello+world.txt").toURI().toString());
        out.println(java.net.URLDecoder.decode(new File("hello+world.txt").toURI().toURL().toString()));
        out.println(new File("hello+world.txt").toURI().toString().replaceAll("\\+", "%2B"));
    }
}

答案 3 :(得分:0)

如果URI代表文件,则让File类解码URI。

假设我们有一个文件的URI,例如,获取jar文件的文件路径: URI uri = MyClass.class.getProtectionDomain()。getCodeSource()。getLocation()。toURI();

System.out.println(uri.toString());
=>不良:将显示加号,但空格显示%20

System.out.println(URLDecoder.decode(uri.toString(),StandardCharsets.UTF_8.toString()));
=>不良:将显示空格,而不是%20,但也不显示加号

System.out.println(new File(uri).getAbsolutePath());
=>好的

答案 4 :(得分:-1)

尝试使用反斜杠\来逃避加号

new File("hello\+world.txt").toURI().toString()