URI 的编码路径在内置于 JAR 中或未内置于 JAR 中时表现不同
Encoding Path to URI behaves differently when built into JAR or not
我调用了 HashMap 的 containsKey 方法,我希望 return 为真。如果我将我的程序编译为 .class 文件并且 运行 那样,它 returns 是真的,但是如果我构建一个 JAR 那么相同的调用 returns false 原因看不懂。
我已经调试了 .class 和 JAR 版本(使用 http://www.eclipsezone.com/eclipse/forums/t53459.html 中描述的远程连接的 JAR),在这两种情况下,HashMap 似乎都包含密钥 I'我正在检查。
HashMap 使用 URI 对象作为键。以下是每个调试会话中显示的变量内容:
当 运行 作为 .class 文件时
HashMap 键:java.net.URI = file:/E:/SSD%20App%20Libraries/Google%20Drive/Programming/Bet%20Matching/Java%20Sim/target/classes/simfiles/paytables/
URIToCheck:java.net.URI = file:///E:/SSD%20App%20Libraries/Google%20Drive/Programming/Bet%20Matching/Java%20Sim/target/classes/simfiles/paytables/
结果:GameTreeItemsMap.containsKey(URIToCheck)
是true
当 运行 作为 JAR
HashMap 键:java.net.URI = jar:file:/E:/SSD%20App%20Libraries/Google%20Drive/Programming/Bet%20Matching/Java%20Sim/out/artifacts/JavaSim_jar/Java%20Sim.jar!/simfiles/paytables/
URIToCheck:java.net.URI = jar:file:///E:/SSD%2520App%2520Libraries/Google%2520Drive/Programming/Bet%2520Matching/Java%2520Sim/out/artifacts/JavaSim_jar/Java%2520Sim.jar!/simfiles/paytables/
结果:GameTreeItemsMap.containsKey(URIToCheck)
是false
在这两种情况下,我希望该方法 return true
。 URI 在 JAR 中的行为是否有所不同?怎么回事?
在此先感谢您的帮助!
编辑 1
正如向我指出的那样,JAR 案例中的 URIToCheck 被双重编码(%2520 而不是 %20)。下面是生成 URIToCheck 的代码。我使用 walkFileTree
方法。
Files.walkFileTree(paytableHomePath, new SimpleFileVisitor<Path>(){
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
Path parentPath = dir.getParent();
URI parentURIToCheck = parentPath.toUri();
boolean testContain = GameTreeItemsMap.containsKey(parentURIToCheck);
return FileVisitResult.CONTINUE;
}
在 JAR 的情况下,URI parentURIToCheck
是双重编码的(对于 space 应该有 %20 的是 %5250),在 .class 的情况下是这样的不会发生。知道为什么吗?
这与HashMap无关。您似乎在 Java 的 Zip File System Provider 中发现了一个错误,即它将路径转换为双重编码的 URI。
我找不到它的现有错误,所以我提交了一个。 (有this related bug, whose fix I suspect is the cause of this one.) Update: This is Java bug 8131067.
这是我在 Java 1.8.0_45-b14 中编写的用于演示问题的程序。将路径中包含一个或多个空格的 .jar 文件作为第一个命令行参数传递。
import java.util.Map;
import java.util.Collections;
import java.net.URI;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
public class JarPathTest {
public static void main(String[] args)
throws IOException {
Path zip = Paths.get(args[0]);
URI zipURI = URI.create("jar:" + zip.toUri());
System.out.println(zipURI);
Map<String, String> env = Collections.emptyMap();
try (FileSystem fs = FileSystems.newFileSystem(zipURI, env)) {
Path root = fs.getPath("/");
System.out.println(root.toUri());
}
}
}
您可以通过将解码后的 URI 视为仍然是百分比编码来解决此问题:
parentURIToCheck = URI.create(
parentURIToCheck.getScheme() + ":" +
parentURIToCheck.getSchemeSpecificPart());
我调用了 HashMap 的 containsKey 方法,我希望 return 为真。如果我将我的程序编译为 .class 文件并且 运行 那样,它 returns 是真的,但是如果我构建一个 JAR 那么相同的调用 returns false 原因看不懂。
我已经调试了 .class 和 JAR 版本(使用 http://www.eclipsezone.com/eclipse/forums/t53459.html 中描述的远程连接的 JAR),在这两种情况下,HashMap 似乎都包含密钥 I'我正在检查。
HashMap 使用 URI 对象作为键。以下是每个调试会话中显示的变量内容:
当 运行 作为 .class 文件时
HashMap 键:java.net.URI = file:/E:/SSD%20App%20Libraries/Google%20Drive/Programming/Bet%20Matching/Java%20Sim/target/classes/simfiles/paytables/
URIToCheck:java.net.URI = file:///E:/SSD%20App%20Libraries/Google%20Drive/Programming/Bet%20Matching/Java%20Sim/target/classes/simfiles/paytables/
结果:GameTreeItemsMap.containsKey(URIToCheck)
是true
当 运行 作为 JAR
HashMap 键:java.net.URI = jar:file:/E:/SSD%20App%20Libraries/Google%20Drive/Programming/Bet%20Matching/Java%20Sim/out/artifacts/JavaSim_jar/Java%20Sim.jar!/simfiles/paytables/
URIToCheck:java.net.URI = jar:file:///E:/SSD%2520App%2520Libraries/Google%2520Drive/Programming/Bet%2520Matching/Java%2520Sim/out/artifacts/JavaSim_jar/Java%2520Sim.jar!/simfiles/paytables/
结果:GameTreeItemsMap.containsKey(URIToCheck)
是false
在这两种情况下,我希望该方法 return true
。 URI 在 JAR 中的行为是否有所不同?怎么回事?
在此先感谢您的帮助!
编辑 1
正如向我指出的那样,JAR 案例中的 URIToCheck 被双重编码(%2520 而不是 %20)。下面是生成 URIToCheck 的代码。我使用 walkFileTree
方法。
Files.walkFileTree(paytableHomePath, new SimpleFileVisitor<Path>(){
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
Path parentPath = dir.getParent();
URI parentURIToCheck = parentPath.toUri();
boolean testContain = GameTreeItemsMap.containsKey(parentURIToCheck);
return FileVisitResult.CONTINUE;
}
在 JAR 的情况下,URI parentURIToCheck
是双重编码的(对于 space 应该有 %20 的是 %5250),在 .class 的情况下是这样的不会发生。知道为什么吗?
这与HashMap无关。您似乎在 Java 的 Zip File System Provider 中发现了一个错误,即它将路径转换为双重编码的 URI。
我找不到它的现有错误,所以我提交了一个。 (有this related bug, whose fix I suspect is the cause of this one.) Update: This is Java bug 8131067.
这是我在 Java 1.8.0_45-b14 中编写的用于演示问题的程序。将路径中包含一个或多个空格的 .jar 文件作为第一个命令行参数传递。
import java.util.Map;
import java.util.Collections;
import java.net.URI;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
public class JarPathTest {
public static void main(String[] args)
throws IOException {
Path zip = Paths.get(args[0]);
URI zipURI = URI.create("jar:" + zip.toUri());
System.out.println(zipURI);
Map<String, String> env = Collections.emptyMap();
try (FileSystem fs = FileSystems.newFileSystem(zipURI, env)) {
Path root = fs.getPath("/");
System.out.println(root.toUri());
}
}
}
您可以通过将解码后的 URI 视为仍然是百分比编码来解决此问题:
parentURIToCheck = URI.create(
parentURIToCheck.getScheme() + ":" +
parentURIToCheck.getSchemeSpecificPart());