我只想用这个问题来检查我自己的理智。我有一个文件名,其中包含一个+ (加号)字符,它在某些操作系统和文件系统(例如MacOS和HFS+)上完全有效。
然而,我看到一个问题,我认为java.io.File#toURI()的操作不正确。
例如:
new File("hello+world.txt").toURI().toString()在我的Mac机器上返回:
file:/Users/aretter/code/rocksdb/hello+world.txt但是IMHO,这是不正确的,因为文件名中的+ (加号)字符没有在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+world.txt因此,在以后使用和解码时,加号将被保留。
我很难相信这样一个明显的错误可能存在于Java中。有人能指出我哪里弄错了吗?
另外,如果有解决办法,我想听听吗?请记住,我实际上并不是将静态字符串作为文件名提供给File,而是从磁盘读取文件目录,其中一些文件可能包含一个+ (加号)字符。
发布于 2017-10-23 20:45:16
让我澄清一下,
'+‘+字符是作为URL上下文中的正常字符的威胁,它不以任何形式编码(例如%20)。
因此,当您调用new File("hello+world.txt").toURI().toString()时,它不会对'+‘字符执行任何编码(仅仅因为它不是必需的)。
现在来看看URLDecoder,这个类是一个用于HTML解码的实用类。它将“+”加号视为编码字符,从而将其解码为“”空格字符。在您的示例中,该类将URI的字符串值作为普通的html表单字段的值(而不是URI值)。这个类不应该用于解码完整的URI/URL值,因为它不是为此目的而设计的)
来自URLDecoder#decode的java文档(字符串),
解码x-www格式-urlencoded字符串。平台的默认编码用于确定由窗体"%xy“的任何连续序列表示的字符。
希望能帮上忙。
基于注释的更新#1:
根据第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推荐。
有关答覆:
发布于 2017-10-24 16:33:41
我假设,您希望将+签名编码到%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发布于 2017-10-23 20:32:32
显然,这不是一个bug,文档清楚地说
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"));
}
}https://stackoverflow.com/questions/46644306
复制相似问题