简体   繁体   中英

getResourceAsStream() - InputStream null when using relative path

I am using Maven and running a JUnit test on a static method that tries to read in a file using:

InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);

And then using new InputStreamReader(is) to use as a reader in another call. This works when filename is just a filename (eg file.csv ) but when filename is a relative path (eg src/test/resources/file.csv ), is ends up being null .

I need it to handle relative paths, because I'm running a test suite via JUnit that looks for resources with relative paths and these tests are coming from a JAR that I have no control over changing (ie I implemented a facade implementation class that the test suite uses to call its own tests with its own resources - they are out of my control).

Is there a way for this approach to work with relative paths, or some other way that I can find those resources on my classpath that the tests are looking for?

Running tests in maven, src/test/resources/ is (by default) "mapped" to the root of the class(loader)path, so in your case /file.csv is the correct absolute path of src/test/resources/file.csv .

To load "src/test/resources/file.csv" (Resource) successfully ( which is comple nonsense ), you should have this file (physically) available: src/test/resources/src/test/resources/file.csv , or respectively src/main/java (which would also be mapped to cp root) ... /src/test/resources/file.csv

In your case is ends up being null because when a resource lookup is performed, the resources directory is entry point, so the complete path is expected to be test/resources/src/test/resources/file.csv or test/resources/src/test/resources/file.csv depending on how you run your tests.

The only reliable way you could achieve your goal is to take care about the correctness manually. Perhaps something like this:

static String getResourceFileName(String maybePath) {
    Path path = Paths.get(maybePath);
    if (path.getNameCount() > 0) {
        return path.getFileName().toString();
    } else {
        throw new IllegalArgumentException("Can't derive filename given " + maybePath);
    }
}

@Test
public void testSoq() throws Exception {
    String fileName0 = getResourceFileName("file");
    InputStream is0 = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName0);

    String fileName1 = getResourceFileName("src/test/resources/file");
    InputStream is1 = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName1);
    String string0 = new BufferedReader(new InputStreamReader(is0)).readLine();
    String string1 = new BufferedReader(new InputStreamReader(is1)).readLine();
    assertEquals(string0, string1); // OK
}

Maybe you'll have to write it according to the specifics of your case (account for possible nested diretories etc.), but I really think that given your inputs may be of arbitrary nature, this won't get much simpler.

I have this on blog (in spanish)

http://lacuevadeyogui.blogspot.com/2015/04/diferencia-entre-uri-y-url.html

The problem in with the reference to file in src/test/resources

try this

URL url = getClass().getClassLoader().getResource("file.csv");
File f;
try {
    f = new File(url.toURI());
} catch (URISyntaxException e) {
    f = new File(url.getPath());
}

At the end, convert file to inputStream.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM