read file from assets
Asked Answered
E

18

213
public class Utils {
    public static List<Message> getMessages() {
        //File file = new File("file:///android_asset/helloworld.txt");
        AssetManager assetManager = getAssets();
        InputStream ims = assetManager.open("helloworld.txt");    
     }
}

I am using this code trying to read a file from assets. I tried two ways to do this. First, when use File I received FileNotFoundException, when using AssetManager getAssets() method isn't recognized. Is there any solution here?

Ectomy answered 3/3, 2012 at 8:45 Comment(0)
Q
258

Here is what I do in an activity for buffered reading extend/modify to match your needs

BufferedReader reader = null;
try {
    reader = new BufferedReader(
        new InputStreamReader(getAssets().open("filename.txt")));

    // do reading, usually loop until end of file reading  
    String mLine;
    while ((mLine = reader.readLine()) != null) {
       //process line
       ...
    }
} catch (IOException e) {
    //log the exception
} finally {
    if (reader != null) {
         try {
             reader.close();
         } catch (IOException e) {
             //log the exception
         }
    }
}

EDIT : My answer is perhaps useless if your question is on how to do it outside of an activity. If your question is simply how to read a file from asset then the answer is above.

UPDATE :

To open a file specifying the type simply add the type in the InputStreamReader call as follow.

BufferedReader reader = null;
try {
    reader = new BufferedReader(
        new InputStreamReader(getAssets().open("filename.txt"), "UTF-8")); 

    // do reading, usually loop until end of file reading 
    String mLine;
    while ((mLine = reader.readLine()) != null) {
       //process line
       ...
    }
} catch (IOException e) {
    //log the exception
} finally {
    if (reader != null) {
         try {
             reader.close();
         } catch (IOException e) {
             //log the exception
         }
    }
}

EDIT

As @Stan says in the comment, the code I am giving is not summing up lines. mLine is replaced every pass. That's why I wrote //process line. I assume the file contains some sort of data (i.e a contact list) and each line should be processed separately.

In case you simply want to load the file without any kind of processing you will have to sum up mLine at each pass using StringBuilder() and appending each pass.

ANOTHER EDIT

According to the comment of @Vincent I added the finally block.

Also note that in Java 7 and upper you can use try-with-resources to use the AutoCloseable and Closeable features of recent Java.

CONTEXT

In a comment @LunarWatcher points out that getAssets() is a class in context. So, if you call it outside of an activity you need to refer to it and pass the context instance to the activity.

ContextInstance.getAssets();

This is explained in the answer of @Maneesh. So if this is useful to you upvote his answer because that's him who pointed that out.

Qoph answered 3/3, 2012 at 8:53 Comment(12)
This code fails cuz it gonna replace contents of mLine every passFinke
@Stan, then write about it in the comments and let the author to decide if they'd like to update it. Edits are for improving clarity, not changing meaning. Code revisions should always be posted as comments first.Tolerate
Ok, I got it, thanx! Its good you'd mentioned about functionality in EDIT. Im gonna remove this my comment soon as unconstructive etc. Also I voted up your comment aboveFinke
Your code doesn't guaranty to close the stream and free the resource in a timely manner. I recommend you to use finally {reader.close();}.Anacoluthia
@Vincent. doing this on my iPad I'm not able to check the compile. Can you double check me once again please ? Oh and we can remove the useless comments.Qoph
I think it's useful to point out that the code above shows an error in ADT - the "reader.close();" line needs to be put in another try-catch block. Check this thread: #8982089 :)Yen
getAssets is a class in Context, so for usage outside activity a call to Context needs to be made. So outside an activity, it will be something like context.getAssets(.....)African
As per your update (thanks for adding that btw), having context in static fields is a memory leak. This should be used with caution and be properly cleaned up. Otherwise you end up with a memory leak that can have a great impact on the app.African
@LunarWatcher I think that what you point out is important. You should add an answer explaining that, as a complement to what Maneesh and myself have written. So write a full answer and keep me up to date when it's done and I'll modify my answer to point to yours for that point.Qoph
This method mess up html by removing some white spaces!Mucous
@amitpandya You should open a question on that and give your code so we can help you out.Qoph
Say, about try-with-resources, it seems Android Studio says that just like the stream, the AssetManager should also be closed. However, if I do this, I will be able to use AssetManager only once. How come? Should I avoid closing AssetManager in any way?Treva
B
69
getAssets()

is only works in Activity in other any class you have to use Context for it.

Make a constructor for Utils class pass reference of activity (ugly way) or context of application as a parameter to it. Using that use getAsset() in your Utils class.

Boyfriend answered 3/3, 2012 at 8:52 Comment(5)
It works on anything that's a subclass of Context, of which Activity is one of many.Incantation
Just noted I have written Context.Boyfriend
@Boyfriend do you know, how I can convert InputStream into FileInputStream?Hydantoin
@Boyfriend in what way this is ugly?Balcke
Passing UI objects around without considering the consequences is generally a bad practice. If you're not careful, you can cause memory leaks or attempt to use dead contexts. Good read on the topic: android.jlelse.eu/memory-leak-patterns-in-android-4741a7fcb570Nabors
G
63

Better late than never.

I had difficulties reading files line by line in some circumstances. The method below is the best I found, so far, and I recommend it.

Usage: String yourData = LoadData("YourDataFile.txt");

Where YourDataFile.txt is assumed to reside in assets/

 public String LoadData(String inFile) {
        String tContents = "";

    try {
        InputStream stream = getAssets().open(inFile);

        int size = stream.available();
        byte[] buffer = new byte[size];
        stream.read(buffer);
        stream.close();
        tContents = new String(buffer);
    } catch (IOException e) {
        // Handle exceptions here
    }

    return tContents;

 }
Ginn answered 12/7, 2013 at 9:21 Comment(4)
My return string is android.content.res.AssetManager$AssetInputStream@4195dfa0 ..Likeminded
same here, res.AssetManager$AssetInputStream@.... any particular reason why it is returning this?Conciliar
You double-allocate memory - first for the buffer and then for the String. Does not work for bigger files.Rennet
perfect way to allocate size to buffer stream.available().Agone
M
41
public String ReadFromfile(String fileName, Context context) {
    StringBuilder returnString = new StringBuilder();
    InputStream fIn = null;
    InputStreamReader isr = null;
    BufferedReader input = null;
    try {
        fIn = context.getResources().getAssets()
                .open(fileName, Context.MODE_WORLD_READABLE);
        isr = new InputStreamReader(fIn);
        input = new BufferedReader(isr);
        String line = "";
        while ((line = input.readLine()) != null) {
            returnString.append(line);
        }
    } catch (Exception e) {
        e.getMessage();
    } finally {
        try {
            if (isr != null)
                isr.close();
            if (fIn != null)
                fIn.close();
            if (input != null)
                input.close();
        } catch (Exception e2) {
            e2.getMessage();
        }
    }
    return returnString.toString();
}
Machine answered 6/4, 2012 at 12:32 Comment(2)
You would think that if you close the BufferedReader, than it would have to automatically close the InputStreanReader and InputStream too. Because what it you don't create a handle for those, e.g. input = new BufferedReader(new InputStreamReader(fIn));.Pacification
I would suggest creating separate try/catch blocks for closing all of your resources at the end; rather than lumping them all into one - as it may leave other resources unclosed if a prior attempt to close another resource throws an exception.Pouched
P
41

one line solution for kotlin:

fun readFileText(fileName: String): String {
    return assets.open(fileName).bufferedReader().use { it.readText() }
}

Also you can use it as extension function everyWhere

fun Context.readTextFromAsset(fileName : String) : String{
     return assets.open(fileName).bufferedReader().use { 
     it.readText()}
}

Simply call in any context Class

context.readTextFromAsset("my file name")
Penman answered 17/4, 2019 at 6:18 Comment(0)
R
12
AssetManager assetManager = getAssets();
InputStream inputStream = null;
try {
    inputStream = assetManager.open("helloworld.txt");
}
catch (IOException e){
    Log.e("message: ",e.getMessage());
}
Ridgway answered 3/3, 2012 at 8:56 Comment(0)
C
7

getAssets() method will work when you are calling inside the Activity class.

If you calling this method in non-Activity class then you need to call this method from Context which is passed from Activity class. So below is the line by you can access the method.

ContextInstance.getAssets();

ContextInstance may be passed as this of Activity class.

Circassian answered 3/3, 2012 at 8:54 Comment(0)
N
5

Reading and writing files have always been verbose and error-prone. Avoid these answers and just use Okio instead:

public void readLines(File file) throws IOException {
  try (BufferedSource source = Okio.buffer(Okio.source(file))) {
    for (String line; (line = source.readUtf8Line()) != null; ) {
      if (line.contains("square")) {
        System.out.println(line);
      }
    }
  }
}
Natika answered 5/5, 2018 at 12:2 Comment(1)
Do you know why this looks more aesthetic and short? Well, because you've omitted, at least, half of the code here. Omitted parts: 1) IOException's try/catch block 2) Closing streams in case exception is thrown 3) This code reads a single line, not the whole file. Performance-wise, this library is definitely one of its kind, no doubt on that. Now, tell me should I still avoid "these answers" and implement Okio just for reading files? The answer is NO, unless it's already part of your app.Leduc
O
4

Here is a method to read a file in assets:

/**
 * Reads the text of an asset. Should not be run on the UI thread.
 * 
 * @param mgr
 *            The {@link AssetManager} obtained via {@link Context#getAssets()}
 * @param path
 *            The path to the asset.
 * @return The plain text of the asset
 */
public static String readAsset(AssetManager mgr, String path) {
    String contents = "";
    InputStream is = null;
    BufferedReader reader = null;
    try {
        is = mgr.open(path);
        reader = new BufferedReader(new InputStreamReader(is));
        contents = reader.readLine();
        String line = null;
        while ((line = reader.readLine()) != null) {
            contents += '\n' + line;
        }
    } catch (final Exception e) {
        e.printStackTrace();
    } finally {
        if (is != null) {
            try {
                is.close();
            } catch (IOException ignored) {
            }
        }
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException ignored) {
            }
        }
    }
    return contents;
}
Outlawry answered 19/1, 2015 at 9:29 Comment(1)
This is a good answer, but it is bad approach to use String concatenation. Consider using StringBuilder instead. StringBuilder contentBuilder = new StringBuilder(); while((line = reader.readLine()) != null) { builder.append("\n").append(line); } And at the end you can create new String object by this: content = contentBuilder.toString();Wreckage
R
4

You can load the content from the file. Consider the file is present in asset folder.

public static InputStream loadInputStreamFromAssetFile(Context context, String fileName){
    AssetManager am = context.getAssets();
    try {
        InputStream is = am.open(fileName);
        return is;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

public static String loadContentFromFile(Context context, String path){
    String content = null;
    try {
        InputStream is = loadInputStreamFromAssetFile(context, path);
        int size = is.available();
        byte[] buffer = new byte[size];
        is.read(buffer);
        is.close();
        content = new String(buffer, "UTF-8");
    } catch (IOException ex) {
        ex.printStackTrace();
        return null;
    }
    return content;
}

Now you can get the content by calling the function as follow

String json= FileUtil.loadContentFromFile(context, "data.json");

Considering the data.json is stored at Application\app\src\main\assets\data.json

Rabin answered 25/5, 2017 at 10:16 Comment(0)
F
3

In MainActivity.java

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tvView = (TextView) findViewById(R.id.tvView);

        AssetsReader assetsReader = new AssetsReader(this);
        if(assetsReader.getTxtFile(your_file_title)) != null)
        {
            tvView.setText(assetsReader.getTxtFile(your_file_title)));
        }
    }

Also, you can create separate class that does all the work

public class AssetsReader implements Readable{

    private static final String TAG = "AssetsReader";


    private AssetManager mAssetManager;
    private Activity mActivity;

    public AssetsReader(Activity activity) {
        this.mActivity = activity;
        mAssetManager = mActivity.getAssets();
    }

    @Override
    public String getTxtFile(String fileName)
    {
        BufferedReader reader = null;
        InputStream inputStream = null;
        StringBuilder builder = new StringBuilder();

        try{
            inputStream = mAssetManager.open(fileName);
            reader = new BufferedReader(new InputStreamReader(inputStream));

            String line;

            while((line = reader.readLine()) != null)
            {
                Log.i(TAG, line);
                builder.append(line);
                builder.append("\n");
            }
        } catch (IOException ioe){
            ioe.printStackTrace();
        } finally {

            if(inputStream != null)
            {
                try {
                    inputStream.close();
                } catch (IOException ioe){
                    ioe.printStackTrace();
                }
            }

            if(reader != null)
            {
                try {
                    reader.close();
                } catch (IOException ioe)
                {
                    ioe.printStackTrace();
                }
            }
        }
        Log.i(TAG, "builder.toString(): " + builder.toString());
        return builder.toString();
    }
}

In my opinion it's better to create an interface, but it's not neccessary

public interface Readable {
    /**
     * Reads txt file from assets
     * @param fileName
     * @return string
     */
    String getTxtFile(String fileName);
}
Farias answered 11/10, 2016 at 16:24 Comment(0)
G
3

Here is a way to get an InputStream for a file in the assets folder without a Context, Activity, Fragment or Application. How you get the data from that InputStream is up to you. There are plenty of suggestions for that in other answers here.

Kotlin

val inputStream = ClassLoader::class.java.classLoader?.getResourceAsStream("assets/your_file.ext")

Java

InputStream inputStream = ClassLoader.class.getClassLoader().getResourceAsStream("assets/your_file.ext");

All bets are off if a custom ClassLoader is in play.

Garry answered 11/9, 2018 at 15:45 Comment(0)
A
3

ExceptionProof

It maybe too late but for the sake of others who look for the peachy answers.

loadAssetFile() method returns the plain text of the asset, or defaultValue argument if anything goes wrong.

public static String loadAssetFile(Context context, String fileName, String defaultValue) {
    String result=defaultValue;
    InputStreamReader inputStream=null;
    BufferedReader bufferedReader=null;
    try {
        inputStream = new InputStreamReader(context.getAssets().open(fileName));
        bufferedReader = new BufferedReader(inputStream);
        StringBuilder out= new StringBuilder();
        String line = bufferedReader.readLine();
        while (line != null) {
            out.append(line);
            line = bufferedReader.readLine();
        }
        result=out.toString();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            Objects.requireNonNull(inputStream).close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            Objects.requireNonNull(bufferedReader).close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return result;
}
Arlyne answered 2/1, 2020 at 19:18 Comment(0)
C
2

If you use other any class other than Activity, you might want to do like,

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( YourApplication.getInstance().getAssets().open("text.txt"), "UTF-8"));
Cornellcornelle answered 25/6, 2016 at 6:46 Comment(0)
P
2

Using Kotlin, you can do the following to read a file from assets in Android:

try {
    val inputStream:InputStream = assets.open("helloworld.txt")
    val inputString = inputStream.bufferedReader().use{it.readText()}
    Log.d(TAG,inputString)
} catch (e:Exception){
    Log.d(TAG, e.toString())
}
Plush answered 16/1, 2018 at 4:0 Comment(0)
G
1

cityfile.txt

   public void getCityStateFromLocal() {
        AssetManager am = getAssets();
        InputStream inputStream = null;
        try {
            inputStream = am.open("city_state.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
        ObjectMapper mapper = new ObjectMapper();
        Map<String, String[]> map = new HashMap<String, String[]>();
        try {
            map = mapper.readValue(getStringFromInputStream(inputStream), new TypeReference<Map<String, String[]>>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        ConstantValues.arrayListStateName.clear();
        ConstantValues.arrayListCityByState.clear();
        if (map.size() > 0)
        {
            for (Map.Entry<String, String[]> e : map.entrySet()) {
                CityByState cityByState = new CityByState();
                String key = e.getKey();
                String[] value = e.getValue();
                ArrayList<String> s = new ArrayList<String>(Arrays.asList(value));
                ConstantValues.arrayListStateName.add(key);
                s.add(0,"Select City");
                cityByState.addValue(s);
                ConstantValues.arrayListCityByState.add(cityByState);
            }
        }
        ConstantValues.arrayListStateName.add(0,"Select States");
    }
 // Convert InputStream to String
    public String getStringFromInputStream(InputStream is) {
        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();
        String line;
        try {
            br = new BufferedReader(new InputStreamReader(is));
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return sb + "";

    }
Genitive answered 9/5, 2017 at 13:50 Comment(1)
The link now returns File no longer available That file has now been permanently removed and cannot be recoveredAcademe
D
1

The Scanner class may simplify this.

        StringBuilder sb=new StringBuilder();
        Scanner scanner=null;
        try {
            scanner=new Scanner(getAssets().open("text.txt"));
            while(scanner.hasNextLine()){
                sb.append(scanner.nextLine());
                sb.append('\n');
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(scanner!=null){try{scanner.close();}catch (Exception e){}}
        }
        mTextView.setText(sb.toString());
Duda answered 8/12, 2019 at 3:52 Comment(3)
You can merge these 2 lines sb.append(scanner.nextLine()); sb.append('\n'); to sb.appendln(scanner.nextLine());Rout
there is no such functionDuda
@SinceKotlin("1.4") the appendLine function is added, and appendln is deprecatedRout
A
-1

@HpTerm answer Kotlin version:

private fun getDataFromAssets(activity: Activity): String {

    var bufferedReader: BufferedReader? = null
    var data = ""

    try {
        bufferedReader = BufferedReader(
            InputStreamReader(
                activity?.assets?.open("Your_FILE.html"),
                "UTF-8"
            )
        )                  //use assets? directly if inside the activity

        var mLine:String? = bufferedReader.readLine()
        while (mLine != null) {
            data+= mLine
            mLine=bufferedReader.readLine()
        }

    } catch (e: Exception) {
        e.printStackTrace()
    } finally {
        try {
            bufferedReader?.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
    return data
}
Arbutus answered 5/7, 2019 at 13:4 Comment(3)
Currently this will prepend null to the string. Needed changes: var mLine:String should be var mLine:String? var data: String? should be var data = "" return type should be StringGallfly
It also strips line endings. :(Wallsend
This is not a true Kotlin.Perpetual

© 2022 - 2024 — McMap. All rights reserved.