我只想在这里用这个问题检查自己的理智。我有一个文件名,其中包含+
(加号)字符,在某些操作系统和文件系统(例如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,而是从磁盘读取文件目录,其中一些文件可能包含+
(加号)字符。
答案 0 :(得分:2)
让我试着澄清一下,
'+'加上字符是威胁,作为URL上下文中的普通字符,并且不以任何形式编码(例如%20)。
因此,当您调用new File("hello+world.txt").toURI().toString()
时,不对'+'字符执行任何编码(仅因为它不是必需的)。
现在来URLDecoder
,this 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 :(得分: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()