【发布时间】:2019-06-29 12:16:37
【问题描述】:
我查看了很多关于 Java 文件和路径问题的答案,甚至有些路径中有空格,但没有回答我想问的问题:
为什么以下代码在非空白目录中有效,为什么会失败?
我将我的问题简化为问题的基本要素,所以我希望任何人都可以向我解释这个问题;-)
我有一个旧 API,我必须提供一些图像的文件句柄,我决定通过相对路径 URL 方法加载图像。
我知道这不适用于 jar,但我不打算从 jar 加载任何图像。该解决方案足以满足我当前的要求 而且我现在不想把所有东西都变成流......
但是任何执行的成功都高度依赖于执行的目录!这对我来说似乎很奇怪。
所以我编写了一个 JUnit 测试并提供了一些位于测试资源目录中的文件来研究这个问题。
└───imageload
├───src
│ ├───main
│ │ ├───java
│ │ └───resources
│ └───test
│ ├───java
│ │ └───stupid
│ │ └───test
│ └───resources
│ └───testset
└───target
├───generated-test-sources
│ └───test-annotations
└───test-classes
├───stupid
│ └───test
└───testset
这是使问题显而易见的测试代码:
package stupid.test;
[... imports omitted...]
public class SimpleTest {
public static final File getFileByRelativePathURL(String relativePath) {
URL url = Thread.currentThread().getContextClassLoader().getResource(relativePath);
File file = new File(url.getPath());
return file;
}
@Test
void loadImage() {
File theFile = SimpleTest.getFileByRelativePathURL("testset/black.jpg");
Boolean exists = theFile.exists();
assertTrue(exists);
}
}
在此目录中运行测试时一切正常:
- D:\Temp\working\imageload\
从这里运行它失败了:
- D:\Temp\not working\imageload\
我仔细查看了生成的文件实例,目录中的空间被正确转义到这个文件对象路径:
file = D:\Temp\not%20working\imageload\target\test-classes\testset\black.jpg
但是%20肯定有问题,因为根据File Class的“exists()”方法找不到文件。
我希望问题对你们中的许多人来说是显而易见的,但我仍然希望“theFile.exists()”在任何有或没有空格的目录中返回 true。
我做错了什么?
更新:有人问我我的问题是否与本文重复:
不幸的是,该解决方案没有解决我寻找正确相对路径的冲动。相反,它将绝对路径传递给文件构造函数。
但是结合 JB Nizet 的评论帮助我理解了这个问题......虽然这是一个非常肮脏的解决方案,但我将我的相对 URL 方法更改为:
public static final File getFileByRelativePathURL(String relativePath) {
URL url = Thread.currentThread().getContextClassLoader().getResource(relativePath);
File file = new File(url.getPath().replaceAll("%20", " "));
return file;
}
现在一切正常...愚蠢的我! 我真的必须以另一种方式来做;-)
【问题讨论】:
-
停止将类路径资源 URL 视为文件路径。做正确的事,它会正常工作。返回 URL 或 InputStream,而不是 File。
-
好点,但由于我尝试用文件提供的 API 不喜欢流,我该如何避免这个问题?我知道这些问题看起来很愚蠢,但这就是我想要解决的......
-
如果 API 需要文件只是为了能够从中读取文件,那么它的设计很糟糕,应该将 InputStream 作为参数。您应该修复(或要求修复)API。如果 API 需要文件来写入它们,那么您不应该使用类路径资源来提供 API,而应该使用文件系统上的实际文件。如果您想要一个具有默认内容的文件,您始终可以在提供 API 之前将资源复制到一个文件中。
-
这是个好建议!我知道我能做些什么!至少我会尝试在我自己的代码中使用流!非常感谢您的帮助! :)
-
我认为发布您的“更新”作为答案是有意义的
标签: java junit whitespace java-io junit5