293

I have a unit test that needs to work with XML file located in src/test/resources/abc.xml. What is the easiest way just to get the content of the file into String?

tharindu_DG
  • 8,900
  • 6
  • 52
  • 64
yegor256
  • 102,010
  • 123
  • 446
  • 597
  • 3
    also, http://stackoverflow.com/questions/1656797/how-to-read-a-file-into-string-in-java – Nikita Rybak Oct 08 '10 at 14:12
  • 2
    @Nikita, was going to vote to close despite my answer, but those questions don't mention `getResourceAsStream()` which I believe is the right approach for the OP's question. – Kirk Woll Oct 08 '10 at 14:17
  • 1
    @kirk, getResourceAsStream caches the file in the classloader. That is unnecessary. – Thorbjørn Ravn Andersen Oct 08 '10 at 16:13
  • @Thorbjørn, where is your reference for that? In any case, it certainly is *convenient and portable* which may in fact be necessary. – Kirk Woll Oct 08 '10 at 17:12
  • For Android Studio see following link http://stackoverflow.com/a/33057561/3256989 – ultraon Oct 10 '15 at 18:37
  • yegor256's answer not work. For my situation is `getClass().getClassLoader().getResource("com/example/ninja.txt"));`, my resource file located at com/example/ninja.txt – Ninja Dec 20 '17 at 06:00
  • 3
    This question shouldn't be closed. The "duplicates" provided don't answer how to read a resource file, but files in general. The problem is how to reference that resource file – GabrielBB Jan 15 '20 at 00:20
  • I had to use a leading slash: `Bla.class.getResourceAsStream("/abc.xml")` – mihca Jul 21 '22 at 12:13

12 Answers12

279

Finally I found a neat solution, thanks to Apache Commons:

package com.example;
import org.apache.commons.io.IOUtils;
public class FooTest {
  @Test 
  public void shouldWork() throws Exception {
    String xml = IOUtils.toString(
      this.getClass().getResourceAsStream("abc.xml"),
      "UTF-8"
    );
  }
}

Works perfectly. File src/test/resources/com/example/abc.xml is loaded (I'm using Maven).

If you replace "abc.xml" with, say, "/foo/test.xml", this resource will be loaded: src/test/resources/foo/test.xml

You can also use Cactoos:

package com.example;
import org.cactoos.io.ResourceOf;
import org.cactoos.io.TextOf;
public class FooTest {
  @Test 
  public void shouldWork() throws Exception {
    String xml = new TextOf(
      new ResourceOf("/com/example/abc.xml") // absolute path always!
    ).asString();
  }
}
yegor256
  • 102,010
  • 123
  • 446
  • 597
  • 11
    Can do this as simply without external library dependency. – Glen Best Nov 05 '12 at 06:35
  • Should we close InputStream in this case? – dbf Mar 14 '14 at 12:23
  • @dbf good question... I think we should, but since it's a unit test, we don't really care :) – yegor256 Mar 14 '14 at 12:37
  • In which path have you stored "abc.xml"? – Benny Code Mar 26 '14 at 16:55
  • @BennyNeugebauer see the update of the answer – yegor256 Mar 26 '14 at 17:48
  • 8
    @yegor256 since it's a unit test closing resources is *particularly* important. "Unit" tests should be fast and self contained, leaving resources open, potentially for the duration of the test run, means at best your tests run slower, and at worst fail in difficult-to-diagnose ways. – dimo414 May 27 '14 at 07:24
  • 4
    Just as compact, but with proper closing of the input stream: `IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8")`. – Bogdan Calmac Mar 05 '15 at 17:53
  • 6
    Hey @yegor256, isn't `IOUtils.toString` static method? How would you solve it now, according to your well known `static` dislike? – Radek Postołowicz Feb 15 '16 at 22:20
  • @RadekPostołowicz I can't solve it anyhow else, because all I have from Apache is this static method. Would be great, if they would provide, say, `FileAsString` class, which constructor would be used instead of this static method – yegor256 Feb 16 '16 at 18:49
  • 1
    Just in case if getClass().getResourceAsStream() gives a nullpointer. Try to get it from Thread.currentThread().getContextClassLoader().getResourceAsStream.... – raksja May 10 '16 at 20:52
  • 3
    This only works if the file is located in the same package. What if they are not in the same package – Tiina Sep 22 '16 at 08:17
  • 1
    @RadekPostołowicz to solve that problem I created [Cactoos](http://www.cactoos.org), see the updated answer :) – yegor256 Jun 25 '17 at 17:44
  • 1
    I had to use an absolute path, otherwise `getResource()` would return `null`. So this works correctly for me: `this.getClass().getResource("/my-test-file.txt")` – RedShift Sep 21 '18 at 07:00
  • 1
    This worked for me `IOUtils.toString( this.getClass().getClassLoader().getResourceAsStream("abc.xml"), "UTF-8" );` – Doogle Apr 25 '19 at 03:46
  • This explain well and resolve all confusion https://stackoverflow.com/questions/14739550/difference-between-getclass-getclassloader-getresource-and-getclass-getres – vsk.rahul Jul 05 '19 at 09:11
  • Since java 9 without library :) -> `new String(getClass().getClassLoader().getResourceAsStream(resourceName).readAllBytes());` – GabrielBB Jan 15 '20 at 00:09
  • For Java11 you can use this without an additional dependency: `Path path = Paths.get(getClass().getResource("abc.xml").getPath()); String string = Files.readString(path, StandardCharsets.UTF_8);` – Patrick Dorn Jan 19 '22 at 09:51
  • Solution does not work from static context. – djangofan May 25 '22 at 21:11
  • 1
    Since Apache Commons 2.6 you can use `resourceToString` instead for cleaner code: `String xml = IOUtils.resourceToString("/com/example/abc.xml", StandardCharsets.UTF_8));`. Please note the file path must be absolute in this case. – Jufr Jan 19 '23 at 14:31
167

Right to the point :

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("file/test.xml").getFile());
akash
  • 22,664
  • 11
  • 59
  • 87
pablo.vix
  • 2,103
  • 2
  • 15
  • 12
94

Assume UTF8 encoding in file - if not, just leave out the "UTF8" argument & will use the default charset for the underlying operating system in each case.

Quick way in JSE 6 - Simple & no 3rd party library!

import java.io.File;
public class FooTest {
  @Test public void readXMLToString() throws Exception {
        java.net.URL url = MyClass.class.getResource("test/resources/abc.xml");
        //Z means: "The end of the input but for the final terminator, if any"
        String xml = new java.util.Scanner(new File(url.toURI()),"UTF8").useDelimiter("\\Z").next();
  }
}

Quick way in JSE 7

public class FooTest {
  @Test public void readXMLToString() throws Exception {
        java.net.URL url = MyClass.class.getResource("test/resources/abc.xml");
        java.nio.file.Path resPath = java.nio.file.Paths.get(url.toURI());
        String xml = new String(java.nio.file.Files.readAllBytes(resPath), "UTF8"); 
  }

Quick way since Java 9

new String(getClass().getClassLoader().getResourceAsStream(resourceName).readAllBytes());

Neither intended for enormous files though.

GabrielBB
  • 2,479
  • 1
  • 35
  • 49
Glen Best
  • 22,769
  • 3
  • 58
  • 74
  • 1
    the 2nd example doesn't work, readAllBytes doesn't seem to accept URL... the closest I got to make it work is `String xml = new String(java.nio.file.Files.readAllBytes(Paths.get(url.toURI())), "UTF8");` – Eran Medan Jun 13 '13 at 20:06
  • It does work - needs an argument of type Path. That's why I called it resPath. :) – Glen Best Jun 15 '13 at 00:36
  • Am I missing something? You create the variable `url` and don't use it, and use a variable `resPath` without having creating it. Seems important to include the magic that makes it work. – roundar Aug 06 '13 at 02:14
  • Oop. Fixed - added missing line. Now I understand prior confusion in comments :-$ – Glen Best Aug 06 '13 at 05:11
  • @GlenBest - Could you clarify what an "enormous file" is? – ArtOfWarfare Nov 05 '13 at 20:43
  • 2
    The above reads the file contents directly into a string in memory. So, for example, if you have 4GB of memory, then a file of somewhere between 1-4GB probably classifies as "enormous" because it will consume a very significant proportation of memory resources (page swapping to disk, aside). For large files, better to stream - read in chunks, not all at once. – Glen Best Nov 06 '13 at 03:19
  • 2
    java7 version is perfect, tip: use StandardCharsets.UTF_8 to avoid the unsupportedEncodingException – pdem Feb 02 '16 at 16:01
  • 1
    Can you explain why you're using MyClass rather than for example FoTest and when you want to use which class? – phant0m Aug 03 '16 at 15:12
  • Well done on adding the full package names in your example. That is ALWAYS helpful. – Paul Feb 16 '17 at 22:33
  • I got it working with the slash at the start of the file name `MyClass.class.getResource("/test/resources/abc.xml")` – Alex Po Mar 29 '18 at 10:55
  • the r java 9 solution giving the result as a string directly! – hzitoun Sep 01 '22 at 15:01
16

First make sure that abc.xml is being copied to your output directory. Then you should use getResourceAsStream():

InputStream inputStream = 
    Thread.currentThread().getContextClassLoader().getResourceAsStream("test/resources/abc.xml");

Once you have the InputStream, you just need to convert it into a string. This resource spells it out: http://www.kodejava.org/examples/266.html. However, I'll excerpt the relevent code:

public String convertStreamToString(InputStream is) throws IOException {
    if (is != null) {
        Writer writer = new StringWriter();

        char[] buffer = new char[1024];
        try {
            Reader reader = new BufferedReader(
                    new InputStreamReader(is, "UTF-8"));
            int n;
            while ((n = reader.read(buffer)) != -1) {
                writer.write(buffer, 0, n);
            }
        } finally {
            is.close();
        }
        return writer.toString();
    } else {        
        return "";
    }
}
Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
  • 3
    What is `your output directory`? – yegor256 Oct 08 '10 at 14:42
  • @Vincenzo, usually "classes" though perhaps "bin". i.e. wherever you are compiling your classes to. Most IDEs already copy resource files such as xml files to that directory so you should probably take a quick peak and see if it's already there. – Kirk Woll Oct 08 '10 at 14:47
  • Looks like too much code in your case. I would better use some `apache.commons.io.*` class for file reading, and `java.lang.Class.getResource()`. What do you think? – yegor256 Oct 11 '10 at 11:39
  • A nice way to test it would be if you write the test cases in a ".properties" file with testKey = value and then you can load the InputStream directly. Example: Properties properties = new Properties(); properties.load(inputStream); String testCase = properties.getProperty("testKey"); – Benny Code Mar 26 '14 at 17:13
  • 2
    How to make that `abc.xml` be copied to output directory? @KirkWoll – Jeff Tian Dec 22 '17 at 08:05
13

With the use of Google Guava:

import com.google.common.base.Charsets;
import com.google.common.io.Resources;

public String readResource(final String fileName, Charset charset) throws Exception {
        try {
            return Resources.toString(Resources.getResource(fileName), charset);
        } catch (IOException e) {
            throw new IllegalArgumentException(e);
        }
}

Example:

String fixture = this.readResource("filename.txt", Charsets.UTF_8)
Datageek
  • 25,977
  • 6
  • 66
  • 70
7

You can try doing:

String myResource = IOUtils.toString(this.getClass().getResourceAsStream("yourfile.xml")).replace("\n","");
Guido Celada
  • 2,147
  • 1
  • 18
  • 23
  • 3
    Why are you stripping new lines? – zudduz May 19 '16 at 19:02
  • 3
    @zudduz i'm sorry i don't remember, this was 2 years ago – Guido Celada May 20 '16 at 13:53
  • 1
    IOUtils.toString toString(stream) is also deprecated. A Charsets needed to be passed in IOUtils.toString toString(stream, Charsets.UTF_8) (import com.google.common.base.Charsets;) – rjdkolb Apr 10 '17 at 05:53
  • Actually to avoid deprecation, it should be : String myResource = IOUtils.toString(this.getClass().getResourceAsStream("yourfile.xml"), StandardCharsets.UTF_8).replace("\n",""); – rjdkolb May 05 '21 at 14:45
2

Here's what i used to get the text files with text. I used commons' IOUtils and guava's Resources.

public static String getString(String path) throws IOException {
    try (InputStream stream = Resources.getResource(path).openStream()) {
        return IOUtils.toString(stream);
    }
}
ikryvorotenko
  • 1,393
  • 2
  • 16
  • 27
2

OK, for JAVA 8, after a lot of debugging I found that there's a difference between

URL tenantPathURI = getClass().getResource("/test_directory/test_file.zip");

and

URL tenantPathURI = getClass().getResource("test_directory/test_file.zip");

Yes, the / at the beginning of the path without it I was getting null!

and the test_directory is under the test directory.

KhogaEslam
  • 2,528
  • 1
  • 20
  • 21
1

You can use a Junit Rule to create this temporary folder for your test:

@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
File file = temporaryFolder.newFile(".src/test/resources/abc.xml");
Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
IgorGanapolsky
  • 26,189
  • 23
  • 116
  • 147
  • @JohannesRabauer It accesses the file that OP asked for, on every test run. – IgorGanapolsky Feb 22 '23 at 13:07
  • 1
    in every run of the test, a new temporary folder is created. In this folder a new file "...abc.xml" is created. This means with your code the already existing file in "src/test/resources/abc.xml" is not accessed but a different file is created. – Johannes Rabauer Feb 23 '23 at 14:25
1

Using Commons.IO, this method works from EITHER a instance method or a static method:

public static String loadTestFile(String fileName) {
    File file = FileUtils.getFile("src", "test", "resources", fileName);
    try {
        return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
    } catch (IOException e) {
        log.error("Error loading test file: " + fileName, e);
        return StringUtils.EMPTY;
    }
}
djangofan
  • 28,471
  • 61
  • 196
  • 289
1

Simplest, using Apache Commons IO:

IOUtils.resourceToString("/foo/text.txt", StandardCharsets.UTF_8);
Daniel Hári
  • 7,254
  • 5
  • 39
  • 54
0

If you're using okio in your project:

val text = FileSystem.RESOURCES.source("abc.xml".toPath()
  .buffer()
  .readString()
Saket
  • 2,945
  • 1
  • 29
  • 31