将URL转换为普通的Windows文件名Java

63

有没有一种方法可以将这个转换为:

/C:/Users/David/Dropbox/My%20Programs/Java/Test/bin/myJar.jar

翻译成这个样子?

C:\Users\David\Dropbox\My Programs\Java\Test\bin\myJar.jar

我正在使用以下代码,该代码将返回.JAR存档文件的完整路径或/bin目录的路径。

fullPath = new String(MainInterface.class.getProtectionDomain()
            .getCodeSource().getLocation().getPath());
问题在于,getLocation() 返回一个 URL 类型的值,而我需要一个普通的 Windows 文件名。 我尝试在 getLocation() 后面加上以下代码:

toString()toExternalForm() 都返回:

file:/C:/Users/David/Dropbox/My%20Programs/Java/Test/bin/

getPath()返回:

/C:/Users/David/Dropbox/My%20Programs/Java/Test/bin/
请注意需要将%20转换为空格。是否有快捷简单的方法可以实现这一点?

我试着使用查找和替换空格以及删除第一个字符,但我不太喜欢这种方法。这就是为什么我在这里询问,也许有人知道一些将其转换为更少出错且更高效的方法。 - David
如果有其他获取jar文件完整文件名的替代方法也将不胜感激。 - David
@ David 你的意思是 String WinPath = System.getenv("USERPROFILE"); WinPath = WinPath.replace("\", "\\"); WinPath += "\\Desktop\\SalesReports\\"; - mKorbel
6个回答

92

当前的推荐做法(在JDK 1.7+)是将URL → URI → Path进行转换。因此,要将URL转换为File,您可以使用Paths.get(url.toURI()).toFile()。如果您还不能使用JDK 1.7,则建议使用new File(URI.getSchemeSpecificPart())

将文件(file)转换为URI:首先,我将向您展示一些Java中常见的URI示例。

                          -classpath URLClassLoader File.toURI()                Path.toUri()
C:\Program Files          file:/C:/Program%20Files/ file:/C:/Program%20Files/   file:///C:/Program%20Files/
C:\main.c++               file:/C:/main.c++         file:/C:/main.c++           file:///C:/main.c++
\\VBOXSVR\Downloads       file://VBOXSVR/Downloads/ file:////VBOXSVR/Downloads/ file://VBOXSVR/Downloads/
C:\Résume.txt             file:/C:/R%c3%a9sume.txt  file:/C:/Résume.txt         file:///C:/Résume.txt
\\?\C:\Windows (non-path) file://%3f/C:/Windows/    file:////%3F/C:/Windows/    InvalidPathException

以下是对这些URI的一些观察:

  • URI规范为RFC 1738:URL,已被RFC 2396:URI取代,后者又被RFC 3986:URI所取代。(WHATWG也有一个URI规范,但它没有指定如何解释文件URI。)路径中的任何保留字符都会被百分号编码,当您调用URI.toASCIIString()时,URI中的非ASCII字符将被百分号编码。
  • File.toURI()比Path.toUri()更差,因为File.toURI()返回一个不按照RFC 1738标准的异常URI(返回file:/而不是file:// /),并且不会根据Microsoft首选格式为UNC路径格式化URI。但是,这些UNC URI在Firefox中均无法工作(Firefox需要file://///)。
  • Path比File更严格;您不能使用“\ .\”前缀构造一个无效的Path。 “这些前缀不作为路径本身的一部分使用”,但它们可以传递给Win32 API。

将URI转换为文件:让我们尝试将上述示例转换为文件:

                            new File(URI)            Paths.get(URI)           new File(URI.getSchemeSpecificPart())
file:///C:/Program%20Files  C:\Program Files         C:\Program Files         C:\Program Files
file:/C:/Program%20Files    C:\Program Files         C:\Program Files         C:\Program Files
file:///C:/main.c++         C:\main.c++              C:\main.c++              C:\main.c++
file://VBOXSVR/Downloads/   IllegalArgumentException \\VBOXSVR\Downloads\     \\VBOXSVR\Downloads
file:////VBOXSVR/Downloads/ \\VBOXSVR\Downloads      \\VBOXSVR\Downloads\     \\VBOXSVR\Downloads
file://///VBOXSVR/Downloads \\VBOXSVR\Downloads      \\VBOXSVR\Downloads\     \\VBOXSVR\Downloads
file://%3f/C:/Windows/      IllegalArgumentException IllegalArgumentException \\?\C:\Windows
file:////%3F/C:/Windows/    \\?\C:\Windows           InvalidPathException     \\?\C:\Windows

使用Paths.get(URI)new File(URI)更好,因为Path能够处理UNC URI并拒绝具有\?\前缀的无效路径。但如果您不能使用Java 1.7,则使用new File(URI.getSchemeSpecificPart())

顺便说一句,不要使用URLDecoder来解码文件URL。对于包含“+”的文件(例如“file:///C:/main.c++”),URLDecoder会将其转换为“C:\main.c  ”!URLDecoder仅用于解析在URI查询中的application/x-www-form-urlencoded HTML表单提交(param=value&param=value),而不是用于取消引用URI路径。

2014-09: 编辑以添加示例。


5
当然,所有这些都会引发一个该死的URISyntaxException。 - sproketboy
Paths.get() 使用默认文件系统,因此如果您使用它,则无法使用内存文件系统测试代码。 - opticyclic

17
String path = "/c:/foo%20bar/baz.jpg";
path = URLDecoder.decode(path, "utf-8");
path = new File(path).getPath();
System.out.println(path); // prints: c:\foo bar\baz.jpg

这个答案很危险。请向下滚动查看@yonran的答案。 - kritzikratzi
4
你的意思是要往上滚动。 - Dave Yarwood

3

我觉得目前的答案有些靠不住。

java.net.URL.getFile

将文件URL转换为以下格式

java.net.URL = file:/C:/some/resource.txt

转换为这样

java.lang.String = /C:/some/resource.txt

所以您可以使用这个构造函数

new File(url.getFile)

为您提供Windows路径

java.io.File = C:\some\resource.txt

4
这是不正确的。它没有解决空格的不正确(%20)表示方式。我猜那些投赞成票的人和答案的作者一样;没有读清问题。 - Charles Goodwin

3

如前所述,getLocation()会返回一个URL。File可以轻松地将URI转换为路径,所以对我来说最简单的方法就是直接使用:

File fullPath = new File(MainInterface.class.getProtectionDomain().
    getCodeSource().getLocation().toURI());

当然,如果您确实需要字符串,请修改为以下内容:
String fullPath = new File(MainInterface.class.getProtectionDomain().
    getCodeSource().getLocation().toURI()).toString();

你根本不需要使用URLDecoder。

这比其他答案简单得多,而且对我真的有用。 - user1062589

2

大家好,这里涉及到文件路径配置的细微差别。你设置TESSDATA_PREFIX路径是C++ tesseract程序内部使用的,而不是java包装器使用的。这意味着如果你在使用Windows系统,则需要将前斜杠替换为反斜杠,同时将所有其他斜杠也替换为反斜杠。一个非常hacky的解决方法如下:

URL pathUrl = this.getClass().getResource(TESS_DATA_PATH);
String pathStr = pathUrl.getPath();

// hack to get around windows using \ instead of /
if (SystemUtils.IS_OS_WINDOWS) {
  pathStr = pathStr.substring(1);
  pathStr = pathStr.replaceAll("/", "\\\\");
}

2
以下代码是您所需要的:
String path = URLDecoder.decode("/C:/Users/David/Dropbox/My%20Programs/Java/Test/bin/", "UTF-8");
System.out.println(new File(path).getPath());

谢谢。使用 .getAbsolutePath() 是完美的。 - David
类型URLDecoder中的方法decode(String)已被弃用。使用new File()会更好。 - David
@David,你仍然需要解码。只需使用正确的参数(如我的答案所示)。 - Bozho
1
我已经更新了答案,使用getPath方法将不会抛出异常,并且更改了decode方法以指定编码(该变体未被弃用)。 - Andrey Adamovich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接