12

I am getting this error on the following code (note that this does not happen on my local machine, only on my build server):

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

And the exception:

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)

I tried to fix it by following this solution; my code now looks like this:

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);

I am getting the following exception:

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)

Nothing seems to work. How am I supposed to build the path to the file?

Community
  • 1
  • 1
Gleeb
  • 9,244
  • 20
  • 79
  • 123
  • 1
    did you note that the exception in question title is not the same as the exception in the post ? please clarify. – ben75 Apr 20 '15 at 11:35
  • You're passing the URI of a **file** as a new **file system**? I do not know how this can make sense. – Tom Apr 20 '15 at 11:36
  • note that the exception mentioned in the description is the one i am getting after following the solution. the first code snippet is the one throwing the exception in the title... i can include the original exception as well if you like – Gleeb Apr 20 '15 at 11:36
  • did you open your jar or directory deployment to see if your file is present or not in it? and at the correct place? – Mançaux Pierre-Alexandre Apr 20 '15 at 11:43
  • works fine on my local machine, so i assume it is something to do with the environment, or else the path would not work on local run as wlel – Gleeb Apr 20 '15 at 11:44
  • @Gleeb The reason it is working on your local machine is probably that you are running it in an IDE and the resource is actualy a file in that mode. see https://stackoverflow.com/questions/22605666/java-access-files-in-jar-causes-java-nio-file-filesystemnotfoundexception – cquezel Oct 05 '20 at 15:14

5 Answers5

22

Don't try to access a resource like a file. Just grab the InputStream and read the data from there:

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
}

This example uses the IOUtils class from Apache commons-io library.

If you are targeting Java 9+ you can alternatively use data = in.readAllBytes​();.

Robert
  • 33,260
  • 14
  • 84
  • 130
6

Generally, it is not correct to assume that every resource is a file. Instead, you should obtain the URL/InputStream for that resource and read the bytes from there. Guava can help:

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


Another possible solution, with the InputStream and apache commons: Convert InputStream to byte array in Java .

From a byte[], simply use the String constructor to obtain the content as a string.

Community
  • 1
  • 1
botismarius
  • 2,701
  • 2
  • 26
  • 28
3

You should get the resource through an InputStream and not a File, but there is no need for external libraries.

All you need is a couple of lines of code:

InputStream is = getClass().getResourceAsStream("/elasticsearch/segmentsIndex.json");
java.util.Scanner scanner = new java.util.Scanner(is).useDelimiter("\\A");
String json = scanner.hasNext() ? scanner.next() : "";

You can learn more about that method at https://stackoverflow.com/a/5445161/968244

isapir
  • 14,475
  • 6
  • 82
  • 97
3

If you use Spring, inject resources. Be it a file, or folder, or even multiple files, there are chances, you can do it via injection. Warning: DO NOT use File and Files.walk with the injected resources, otherwise you'll get FileSystemNotFoundException when running as JAR.

This example demonstrates the injection of multiple images located in static/img folder.

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());
    }
}
naXa
  • 26,677
  • 15
  • 154
  • 213
  • This is exactly what I needed, didn't know about that injection of `Resources[]`, thanks! – dk7 Mar 22 '20 at 01:52
0

You should be using getResourceAsStream(…) instead of getResource(…). There are a number of methods to read all bytes into a byte array, e.g. Apache Commons has a utility method to do just that.

llogiq
  • 11,855
  • 3
  • 36
  • 65