2017-10-09 101 views
2

我只想在这里检查一下我自己的理智。我有一个文件名,其中有一个+(加号)字符,这在一些操作系统和文件系统(例如MacOS和HFS +)上是完全有效的。File.toURI不对加号进行编码

但是,我看到一个问题,我认为java.io.File#toURI()运行不正常。

例如:

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

在我的Mac机返回:

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

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

所以,如果我们解码的URI,加号现在将被替换为(空格)字符,我们已经失去了信息。例如:

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 

使当它在后来被使用和dec时oded加号被保留。

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

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

+0

如果我正确地得到你的问题,你想'你好+ world.txt'到显示为'hello%2Bworld.txt' – Ravi

回答

2

让我试着澄清一下,

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

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

所以,当你打电话给new File("hello+world.txt").toURI().toString()不执行'+'字符的任何编码(仅仅因为它不是必需的)。

现在来URLDecoder, this class是HTML格式解码的工具类。它将'+'加视为编码字符,因此将其解码为''空格字符。在你的例子中,这个类将URI的字符串值作为普通的html表单字段的值(而不是URI值)。这个类不应该被使用,因为它不是为此而设计的完整的URI/URL值进行解码)

java docs of URLDecoder#decode(String)

Decodes a x-www-form-urlencoded string. The platform's default encoding is used to determine what characters are represented by any consecutive sequences of the form "%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
+0

我的问题是'new File(“hello + world.txt”)。toURI()'不能转义URI中的+,因为在转换为URI以保留它时,需要对文件名中的加号进行编码。 – adamretter

+0

@adamretter但是,这正是他的观点,'+'字符**不需要编码。 阅读例如[URI规范BNF](https://www.w3.org/Addressing/URL/5_URI_BNF.html)。那里的'+'有点特别,但仅仅因为它在'search'中有特殊的含义,并且只在'path'中有效。但就是这样,这里'+'是'path'的一部分,它是有效的,不需要编码。 (你会包括例如'?',这可能会有所不同) – Cryptjar

+0

我不同意。 RFC 3986第2.2节清楚地表明'+'是URI中的保留字符:https://tools.ietf.org/html/rfc3986#section-2.2。具体而言,我引用RFC:1)“用相应的百分比编码字节替换保留字符的URI不相等”,以及2)“产生URI的应用程序应百分比编码对应的数据字节到保留集中的字符“。在这种情况下,我认为'File.toURI'是一个URI生成应用程序。 – adamretter

-1

试图逃跑用反斜杠加号\ 所以做

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

甚至没有编译! – adamretter

+0

它确实如果你正确地使用它,它的代码只是在它所编译和工作的字符串里面的一个\内部。 – Dinh

+1

import java.io.File; 公共类的测试{ \t公共静态无效的主要(字符串ARGS []){ \t \t新的文件( “你好\ + world.txt”)toURI()的toString()。 \t}} 的javac Test.java Test.java:5:错误:非法转义字符 – adamretter

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")); 
    } 
} 
+0

我的问题是'新文件( “你好+ world.txt”)toURI()'没有逃脱+在URI中,因为在转换为URI以保留它时,文件名中的加号需要进行编码。 – adamretter

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