67

I need to load an xml file as String in android so I can load it to TBXML xml parser library and parse it. The implementation I have now to read the file as String takes around 2seconds even for a very small xml file of some KBs. Is there any known fast method that can read a file as string in Java/Android?


This is the code I have now:

public static String readFileAsString(String filePath) {
    String result = "";
    File file = new File(filePath);
    if ( file.exists() ) {
        //byte[] buffer = new byte[(int) new File(filePath).length()];
        FileInputStream fis = null;
        try {
            //f = new BufferedInputStream(new FileInputStream(filePath));
            //f.read(buffer);

            fis = new FileInputStream(file);
            char current;
            while (fis.available() > 0) {
                current = (char) fis.read();
                result = result + String.valueOf(current);
            }
        } catch (Exception e) {
            Log.d("TourGuide", e.toString());
        } finally {
            if (fis != null)
                try {
                    fis.close();
                } catch (IOException ignored) {
            }
        }
        //result = new String(buffer);
    }
    return result;
}
Ky -
  • 30,724
  • 51
  • 192
  • 308
Panos
  • 7,227
  • 13
  • 60
  • 95
  • check this http://stackoverflow.com/questions/326390/how-to-create-a-java-string-from-the-contents-of-a-file – Stack User 5674 Oct 16 '12 at 08:32
  • depends on how you currently read the file. post your code so someone can help you. – Dennis Winter Oct 16 '12 at 08:32
  • I don't have the code with me now. I will post it later. But any suggestions are welcome until then :) – Panos Oct 16 '12 at 08:47
  • 1
    Panos, i don't know how you parse your XML file, but try adding at a StringBuffer object each line, instead of adding to a String. StringBuffer is faster. – Apostolos Oct 16 '12 at 08:55
  • please check the code I'm using and advice. I see I have the string concatenation there. I will change that. Any other advice? – Panos Oct 16 '12 at 21:49

7 Answers7

164

The code finally used is the following from:

http://www.java2s.com/Code/Java/File-Input-Output/ConvertInputStreamtoString.htm

public static String convertStreamToString(InputStream is) throws Exception {
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();
    String line = null;
    while ((line = reader.readLine()) != null) {
      sb.append(line).append("\n");
    }
    reader.close();
    return sb.toString();
}

public static String getStringFromFile (String filePath) throws Exception {
    File fl = new File(filePath);
    FileInputStream fin = new FileInputStream(fl);
    String ret = convertStreamToString(fin);
    //Make sure you close all streams.
    fin.close();        
    return ret;
}
szedjani
  • 550
  • 2
  • 6
  • 21
Panos
  • 7,227
  • 13
  • 60
  • 95
  • 4
    Doesn't seem right to me that your first fn closes a stream that it didn't open. In other words, I think getStringFromFile should close the stream. – Tom Mar 11 '13 at 22:04
  • 3
    @Tom Actually the important part in this answer is to show what happens in the loop and creates the string. Anyway , you were right that it is nicer to close the stream in getStringFromFile, so I edited the answer. Thanks. – Panos Mar 12 '13 at 06:33
  • 3
    Won't this add an extra new line at the end of the string? – Jared Rummler Dec 22 '15 at 13:13
  • @JaredRummler Yes it will. Plus it will modify the line endings of your file to '\n' always, which may very well not be what you want. Again, doing something in java is harder than it needs to be. – Dave Branton Nov 09 '17 at 20:40
  • It's safer to use `Uri` in Android. File path may or may not work. – lenooh Jul 23 '19 at 14:02
17

You can use org.apache.commons.io.IOUtils.toString(InputStream is, Charset chs) to do that.

e.g.

IOUtils.toString(context.getResources().openRawResource(<your_resource_id>), StandardCharsets.UTF_8)

For adding the correct library:

Add the following to your app/build.gradle file:

dependencies {
    compile 'org.apache.directory.studio:org.apache.commons.io:2.4'
}

or for the Maven repo see -> this link

For direct jar download see-> https://commons.apache.org/proper/commons-io/download_io.cgi

Eugene Dudnyk
  • 5,553
  • 1
  • 23
  • 48
  • Method is Deprecated, just added Charset-> `public static String toString(InputStream input, Charset encoding)` see -> commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/IOUtils.html#toString(java.io.InputStream, java.nio.charset.Charset) – CrandellWS Apr 18 '16 at 18:09
  • 1
    Maybe now it is, at the time of writing this answer it wasn't. I can update the answer with info from your comment if you don't mind. Or you can write your own answer :) – Eugene Dudnyk Apr 19 '16 at 13:29
  • I don't mind, and it would not matter if I did, IMHO, you should update the answer to keep it relevant regardless, as I would. – CrandellWS Apr 19 '16 at 13:37
  • I did write my own answer http://stackoverflow.com/a/36701219/181562 which contained source was used for obtaining an asset...though for the given question, I do believe that the brevity of your answer renders it the best... – CrandellWS Apr 19 '16 at 13:40
  • Can you please clarify what is 'resource ID' - I create a directory called /assets under /main and have a sampleText.txt file there. How do I call that file as input? Please help. – Zac Dec 13 '17 at 01:15
  • @Zac Resource ID is R.. This will work if you put file in res/raw/ directory. If you want to read file as string from assets, you will have to use IOUtils.toString(context.getAssets().open(“file_name”), StandardCharsets.UTF8). – Eugene Dudnyk Dec 13 '17 at 07:24
  • Yes, I imported the right IOUtils from Apache (compile 'org.apache.directory.studio:org.apache.commons.io:2.4'), and did the same yesterday. Thanks. – Zac Dec 13 '17 at 22:58
16

Reworked the method set originating from -> the accepted answer

@JaredRummler An answer to your comment:

Read file As String

Won't this add an extra new line at the end of the string?

To prevent having a newline added at the end you can use a Boolean value set during the first loop as you will in the code example Boolean firstLine

public static String convertStreamToString(InputStream is) throws IOException {
   // http://www.java2s.com/Code/Java/File-Input-Output/ConvertInputStreamtoString.htm
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();
    String line = null;
    Boolean firstLine = true;
    while ((line = reader.readLine()) != null) {
        if(firstLine){
            sb.append(line);
            firstLine = false;
        } else {
            sb.append("\n").append(line);
        }
    }
    reader.close();
    return sb.toString();
}

public static String getStringFromFile (String filePath) throws IOException {
    File fl = new File(filePath);
    FileInputStream fin = new FileInputStream(fl);
    String ret = convertStreamToString(fin);
    //Make sure you close all streams.
    fin.close();
    return ret;
}
Community
  • 1
  • 1
CrandellWS
  • 2,708
  • 5
  • 49
  • 111
11

It's very easy if you use Kotlin:

val textFile = File(cacheDir, "/text_file.txt")
val allText = textFile.readText()
println(allText)

From readText() docs:

Gets the entire content of this file as a String using UTF-8 or specified charset. This method is not recommended on huge files. It has an internal limitation of 2 GB file size.

vovahost
  • 34,185
  • 17
  • 113
  • 116
  • 4
    he's not using Kotlin. Question is for Java. – Stealth Rabbi Jan 07 '20 at 20:30
  • 5
    @StealthRabbi In the question the op is asking how to do it in Java/Android. At the time Java was the primary language for Android, so it makes sense to post the Kotlin version now. Also the question tags only include Android which I assume is what's more important. – vovahost Jan 08 '20 at 04:54
  • 3
    Right, and he didn't use the Java tag because it was assumed, given the age of the question. It's like if I asked how to travel fast between cities in 1870, and you respond 100 years later telling me to take an airplane. – Stealth Rabbi Jan 09 '20 at 12:42
  • 5
    @StealthRabbi For a person reading the above mentioned hypothetical question after 100 years, taking an airplane is the accepted right answer. – yajnesh Apr 14 '20 at 15:14
  • 2
    I wrote the original question in the 1800s. We got some nice solutions back in the day. But this is also a very good acceptable solution so we can see the evolution of the JVM apis and solutions – Panos Oct 05 '20 at 10:00
  • 1
    I had some interesting findings regarding memory use of File.readText() for ones interested in memory footprint optimization.. File.readText() seems to consume 50% more memory vs traditional read (e.g reading to bytearray and converting to string). Reading 12M text file shallow size was 72M vs 42M for the operation. – Erkki Nokso-Koivisto Sep 14 '22 at 15:49
6

With files we know the size in advance, so just read it all at once!

String result;
File file = ...;

long length = file.length();
if (length < 1 || length > Integer.MAX_VALUE) {
    result = "";
    Log.w(TAG, "File is empty or huge: " + file);
} else {
    try (FileReader in = new FileReader(file)) {
        char[] content = new char[(int)length];

        int numRead = in.read(content);
        if (numRead != length) {
            Log.e(TAG, "Incomplete read of " + file + ". Read chars " + numRead + " of " + length);
        }
        result = new String(content, 0, numRead);
    }
    catch (Exception ex) {
        Log.e(TAG, "Failure reading " + this.file, ex);
        result = "";
    }
}
NatNgs
  • 874
  • 14
  • 25
Adam Fanello
  • 79
  • 2
  • 4
  • 2
    No idea why this got downvoted. Sure, the code is cluttered, but this will work (and if he runs out of memory allocating a buffer for a large file, so would the examples that use a StringBuffer). It also won't add an extra new-line, which the top-voted answer does. – Aaa Feb 07 '16 at 14:20
  • the comparison at the end of numRead and length compares chars to bytes. It can happen that those are not equal, when the whole file was read. – machinateur Feb 14 '17 at 15:06
  • FileReader in = new FileReader(file) requires api level 19 – ozmank Aug 15 '17 at 11:56
-2
public static String readFileToString(String filePath) {
    InputStream in = Test.class.getResourceAsStream(filePath);//filePath="/com/myproject/Sample.xml"
    try {
        return IOUtils.toString(in, StandardCharsets.UTF_8);
    } catch (IOException e) {
        logger.error("Failed to read the xml : ", e);
    }
    return null;
}
-14

this is working for me

i use this path

String FILENAME_PATH =  "/mnt/sdcard/Download/Version";

public static String getStringFromFile (String filePath) throws Exception {
    File fl = new File(filePath);
    FileInputStream fin = new FileInputStream(fl);
    String ret = convertStreamToString(fin);
    //Make sure you close all streams.
    fin.close();        
    return ret;

}
benka
  • 4,732
  • 35
  • 47
  • 58
Khan
  • 151
  • 1
  • 4