70

I would like to read the content of a file located in the Assets as a String. For example, a text document located in src/main/assets/

Original Question
I found that this question is mostly used as a 'FAQ' for reading an assets file, therefore I summarized the question above. Below is my original question

I'm trying to read a assets file as string. I have a file in my assets folder: data.opml, and want to read it as a string.

Some things I tried:

 AssetFileDescriptor descriptor = getAssets().openFd("data.opml");
 FileReader reader = new FileReader(descriptor.getFileDescriptor());

And also:

 InputStream input = getAssets().open("data.opml");
 Reader reader = new InputStreamReader(input, "UTF-8");

But without success, so a full example would be appreciated.

Mdlc
  • 7,128
  • 12
  • 55
  • 98

4 Answers4

153

getAssets().open() will return an InputStream. Read from that using standard Java I/O:

Java:

StringBuilder sb = new StringBuilder();
InputStream is = getAssets().open("book/contents.json");
BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8 ));
String str;
while ((str = br.readLine()) != null) {
    sb.append(str);
}
br.close();

Kotlin:

val str = assets.open("book/contents.json").bufferedReader().use { it.readText() }
Win Myo Htet
  • 5,377
  • 3
  • 38
  • 56
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 1
    Thank you very much! But (it's probably me again) I can't get it to work with OPML.importFromFile(xxx, MainTabActivity.this); and xxx replaced with buf or in (Is not capable for the arguments stringbuilder (and for in bufferedreader)) – Mdlc Apr 19 '13 at 17:16
  • 4
    @Mark029348: "can't get it to work" is a useless statement, as was "don't work" in your question. Until you explain **completely and precisely** what you mean, it will be very difficult for anyone to help you further. – CommonsWare Apr 19 '13 at 17:18
  • @Mark029348: I don't know where this `OPML` class comes from. The method name suggests that it expects a file on the filesystem, in which case you cannot use an asset with it (except perhaps by copying the asset to a file, then handing a path to the file to `OPML`). If there is some method that takes the actual `String` of the OPML text instead, use that. In the code snippet I show, the `String` is obtained by calling `toString()` on the `StringBuilder`. – CommonsWare Apr 19 '13 at 17:33
  • This is my OPML file, http://pastebin.com/GacAzq6T it imports the data from a xxx.opml file to a database, I'm trying to load the data of a .opml file from my assets folder to the database. – Mdlc Apr 19 '13 at 17:46
  • 1
    @Mark029348: Change the `protected static void importFromInputStream()` method to be `public`, then use that with the `InputStream` you get from `getAssets().open()`. `importFromFile()` expects the name of a file and cannot be used with an asset directly. – CommonsWare Apr 19 '13 at 17:48
  • I get: "The constructor FileInputStream(InputStream) is undefined" in my OPML.java file. Any idea? – Mdlc Apr 19 '13 at 18:00
  • Additional: I changed `Xml.parse(new InputStreamReader(new FileInputStream(filename)), parser);` to `Xml.parse(new InputStreamReader(input), parser);` But the "something that did work" (see question) in another activity doesn't work anymore! – Mdlc Apr 19 '13 at 18:07
  • 1
    @Mark029348: My guess is that you modified `importFromFile()` in your `OPML` class. I did not tell you to do that. Roll back to your original file. Put your text editing cursor immediately to the right of the `d` in `protected` of the `protected static void importFromInputStream()` method. Press the BACKSPACE key 8 times. Type in `ublic`. This will change the keyword `protected` to `public`. Save your file. Use the newly-public `importFromInputStream()` method in your own code where you were trying to use `importFromFile()`. – CommonsWare Apr 19 '13 at 18:13
  • It's not working, this part ` InputStream input = getAssets().open("backup.opml"); Reader reader = new InputStreamReader(input, "UTF-8"); OPML.importFromFile(input, MainTabActivity.this);` Gives errors (respectively) Unhandled exception type IOexception (get till ;), unsupported encoding exception (new till ;) and SAXexception (opml till ;). – Mdlc Apr 19 '13 at 18:18
  • @Mark029348: You need to add exception handling to your app. You already know how to do this, from the Java course you took (should have been covered within the first couple of hours of lecture), or the Java book you read, or however you learned Java. – CommonsWare Apr 19 '13 at 18:20
  • Did so, errors are gone but backup.opml is not being handled. I'll let a friend of me have a look at it later. Thank you very much for helping out! – Mdlc Apr 19 '13 at 18:26
  • I've got it to work! Thank you again, I hope this might help somebody else to. – Mdlc Apr 20 '13 at 06:21
  • @berserk: Assets do not require a permission. – CommonsWare May 14 '14 at 12:44
  • This code will ignore newlines in the source file. I.e. newlines presented in the assets file will not be presented in readed String. Answer from Michael Litvin deals with newlines. – Dmitry Ratty Oct 02 '16 at 19:36
35

There is a little bug CommonsWare's code - newline characters are discarded and not added to the string. Here is some fixed code ready for copy+paste:

private String loadAssetTextAsString(Context context, String name) {
        BufferedReader in = null;
        try {
            StringBuilder buf = new StringBuilder();
            InputStream is = context.getAssets().open(name);
            in = new BufferedReader(new InputStreamReader(is));

            String str;
            boolean isFirst = true;
            while ( (str = in.readLine()) != null ) {
                if (isFirst)
                    isFirst = false;
                else
                    buf.append('\n');
                buf.append(str);
            }
            return buf.toString();
        } catch (IOException e) {
            Log.e(TAG, "Error opening asset " + name);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    Log.e(TAG, "Error closing asset " + name);
                }
            }
        }

        return null;
    }
Michael Litvin
  • 3,976
  • 1
  • 34
  • 40
  • 2
    tl;dr - why not, when does this apply, what to use instead? – Michael Litvin Dec 14 '14 at 06:09
  • 39
    I think you're confusing finally and finalize. Finally is the end of a try catch block and is the perfect place to close resources. Finalize is part of an Object reference and may or may not be called when a Object is GCd and is not the right place at all for closing resources. – Andrew Kelly Mar 09 '15 at 00:20
5

You can also do it, without using loops. It's pretty simple

AssetManager assetManager = getAssets();
InputStream input;
String text = "";

    try {
        input = assetManager.open("test.txt");

        int size = input.available();
        byte[] buffer = new byte[size];
        input.read(buffer);
        input.close();

        // byte buffer into a string
        text = new String(buffer);

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Log.v("TAG", "Text File: " + text);
  • 3
    I don't think you can safely use the available() method like that. See . – realh Nov 13 '15 at 14:35
  • in practice, available() can work fine just to small files, that can fit on SO I/O buffers. – Renascienza Mar 27 '16 at 01:57
  • It might work under certain circumstances in practise, but I would hate to be the developer who has to find and fix the bug that only happens when your file is slightly too large. – Mark McKenna Apr 08 '16 at 15:27
  • 5
    This is old, but I'll still down vote. "available() Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream." Seriously do not use available() in this way. – wndxlori Apr 19 '17 at 16:02
5

hi this is in my opinion the cleanest approach:

  public static String loadTextFromAssets(Context context, String assetsPath, Charset charset) throws IOException {
        InputStream is = context.getResources().getAssets().open(assetsPath);
        byte[] buffer = new byte[1024];
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        for (int length = is.read(buffer); length != -1; length = is.read(buffer)) {
            baos.write(buffer, 0, length);
        }
        is.close();
        baos.close();
        return charset == null ? new String(baos.toByteArray()) : new String(baos.toByteArray(), charset);
    }

because readers could get trouble with line breaks.

Daniel Craig
  • 69
  • 1
  • 4