从资源文件夹获取文件时出现java.nio.file.FileSystemNotFoundException错误

15

以下代码出现错误(注意,这只发生在我的构建服务器上,而不是本地机器上):

Files.readAllBytes(Paths.get(getClass().getResource("/elasticsearch/segmentsIndex.json").toURI()), Charset.defaultCharset());

还有一个例外:

Caused by: java.nio.file.FileSystemNotFoundException: null
at com.sun.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:171)
at com.sun.nio.zipfs.ZipFileSystemProvider.getPath(ZipFileSystemProvider.java:157)
at java.nio.file.Paths.get(Paths.java:143)

我尝试通过遵循这个解决方案来修复它; 我的代码现在看起来像这样:

URI segmentsIndexURI = getClass().getResource("/elasticsearch/segmentsIndex.json").toURI();
Map<String, String> env = new HashMap<>(); 
env.put("create", "true");
FileSystem zipfs = FileSystems.newFileSystem(segmentsIndexURI, env); //exception here
Path segmentsIndexPath = Paths.get(segmentsIndexURI);

我遇到了以下异常:

java.lang.IllegalArgumentException: Path component should be '/'
at sun.nio.fs.UnixFileSystemProvider.checkUri(UnixFileSystemProvider.java:77)
at sun.nio.fs.UnixFileSystemProvider.newFileSystem(UnixFileSystemProvider.java:86)
at java.nio.file.FileSystems.newFileSystem(FileSystems.java:326)
at java.nio.file.FileSystems.newFileSystem(FileSystems.java:276)

似乎什么都没用。 我应该如何构建文件路径?


1
你注意到问题标题中的异常与帖子中的异常不同吗?请澄清。 - ben75
你将一个文件的URI作为新的文件系统传递?我不知道这怎么能有意义。 - Tom
请注意,描述中提到的异常是我在按照解决方案后遇到的异常。第一个代码片段是标题中抛出异常的代码...如果您愿意,我可以包含原始异常。 - Gleeb
你是否打开了你的JAR或目录部署,看看你的文件是否存在于其中?并且在正确的位置吗? - Mançaux Pierre-Alexandre
在我的本地机器上运行良好,因此我认为这与环境有关,否则路径在本地运行时也不起作用。 - Gleeb
@Gleeb 可能之所以在您的本地计算机上运行正常,是因为您正在IDE中运行它,而资源实际上是该模式下的文件。请参见https://dev59.com/SGEh5IYBdhLWcg3wRRqh - cquezel
5个回答

30
不要尝试访问文件这样的资源。只需获取 InputStream 并从那里读取数据:
byte[] data;
try (InputStream in = getClass().getResourceAsStream("/elasticsearch/segmentsIndex.json")) {
    data = in.readAllBytes​(); // usable in Java 9+
    // data = IOUtils.toByteArray(in); // uses Apache commons IO library
}

这个例子使用了Apache commons-io库中的IOUtils类。

如果你的目标是Java 9及以上版本,你可以选择使用data = in.readAllBytes​();


2
我不得不添加 getClass().getClassLoader() - simPod

6

通常,假设每个资源都是文件是不正确的。相反,您应该获取该资源的URL / InputStream并从那里读取字节。Guava可以提供帮助:

URL url = getClass().getResource("/elasticsearch/segmentsIndex.json");
String content = Resources.toString(url, charset);

另一种可能的解决方案,使用InputStream和Apache Commons:在Java中将InputStream转换为byte数组
从byte []中,只需使用String构造函数即可获取内容作为字符串。

3
你应该通过InputStream而不是File来获取资源,但不需要外部库。
你只需要几行代码:
InputStream is = getClass().getResourceAsStream("/elasticsearch/segmentsIndex.json");
java.util.Scanner scanner = new java.util.Scanner(is).useDelimiter("\\A");
String json = scanner.hasNext() ? scanner.next() : "";

您可以在https://dev59.com/UHVC5IYBdhLWcg3wZwJT#5445161了解更多关于该方法的信息。

3
如果您使用Spring,请注入资源。无论是文件、文件夹还是多个文件,都有可能通过注入来实现。警告:不要在注入的资源中使用和,否则在作为JAR运行时会出现错误。
此示例演示了注入位于static/img文件夹中的多个图像。
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;

@Service
public class StackoverflowService {

    @Value("classpath:static/img/*")
    private Resource[] resources;
    private List<String> filenames;

    @PostConstruct
    void init() {
        final Predicate<String> isJPG = path -> path.endsWith(".jpg");
        final Predicate<String> isPNG = path -> path.endsWith(".png");

        // iterate resources, filter by type and get filenames
        filenames = Arrays.stream(resources)
                .map(Resource::getFilename)
                .filter(isJPG.or(isPNG))
                .collect(Collectors.toList());
    }
}

这正是我所需要的,之前不知道有Resources[]注入,谢谢! - dk7

0
你应该使用getResourceAsStream(…)而不是getResource(…)。有许多方法可以将所有字节读入字节数组中,例如Apache Commons有一个实用程序方法可以做到这一点。

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