List assets in a subdirectory using AssetManager.list()

46.5k views Asked by At

My application has an assets directory in which I've dumped a bunch of text files I need to load at runtime.

I have a directory full of assets of a particular type (i.e., "assets/subdir") and I want to load all of the files in this directory, one at a time.

I have code like this:

AssetManager assetMgr = getAssets();
String[] assetsIWant = assetMgr.list("subdir");
for(String asset: assetsIWant) {
  doAssetyThing(asset);
}

I've tried a zillion different versions of the parameter to assetMgr.list() and am not getting anywhere.

If I use "/", I get back a list containing the "assets" directory, and a few random other items (META_INF, for example). If I pass any other string (like "assets" or "assets/" or "/assets" or "/assets/" or "mysubdir" or "/mysubdir" or "assets/mysubdir" or ...) then I get back an empty array.

The documentation is unfortunately fairly incoherent.

Does anybody know what the correct formula for that list() parameter is?

10

There are 10 answers

0
Richard Sharpe On

For some reason, empty directories are not listed.

At least, in my experience, they are not listed.

That is, if you have some-dir/d1/f1 and some-dir/d2 in the assets area, and you list("some-dir"), d2 is not listed.

0
Matt On

There are a lot of similar questions around this topic, I suspect you are using the assets folder in a library project. if you try to access assets in a library project on android you will get empty contents and the exact symptoms you have described here

from the android "projects" documentation

source : http://developer.android.com/tools/projects/index.html

Library projects cannot include raw assets

The tools do not support the use of raw asset files (saved in the assets/ directory) in a library project. Any asset resources used by an application must be stored in the assets/ directory of the application project itself. However, resource files saved in the res/ directory are supported.

if this is the case, the answer is that you should only include Raw assets in the assets folder of your application project NOT in any project marked as a library (you can check this by right clicking your project and selecting properties, select the android entry on the left and look at the is library checkbox)

0
Andro On

This solution seems working for me: Keep a copy of each file you want to access from a sub directory in the assets directory too. Use same convention. i.e. list("subdirectory")

It doesn't read the files in assets folder, but reads all "copied" files in its sub directory. Weird!! But works!

0
ddlw42 On

Passing an empty string seems to work for me. I get a list of the files in my assets directory when I do the following:

AssetManager aMan = appContext.getAssets();
String[] filelist = aMan.list("");
0
Steven_BDawg On

Let's say you have this folder set up: Assets->SubDir1. You have things in Subdir1 like A.txt, B.txt, C.txt. So from the Project's directory, it would be Assets/SubDir1/A.txt.

Taking that into account, the way to access that file is similar to what you're doing, adding one thing. That one thing is in your doAssetyThing function. You have to put the SubDir1 directory in front of it, even if you did a filter of "SubDir1" in the .list("");

Example:

    AssetManager am = getResources().getAssets();
    String [] list = am.list("SubDir1");
    for (String s:list) {
        doAssetyThing("SubDir1/" + s);

        //I use this next line as the start of copying a pdf from one location
        //to another. I wanted to give you a real function in use.

        InputStream inStream = am.open("SubDir1/" + s);

        //more code
    }

I hope this is clear and helps you out!

0
Robin On

When you need to have access to a folder down deeper in your hierarchy use

String[] fileNames =getAssets().list("myFolder"+File.separator+"mysubfolder");

instead of "/" inside the String, which would give you an empty String array as result.

0
32kda On

I use the following two methods to ensure given asset is present:

    protected boolean hasAsset(String id) {
    return hasAsset(id,"");
}

protected boolean hasAsset(String id, String dir) {
    int idx = id.indexOf('/');
    if (idx > 0 && idx < id.length() - 1) {
        if (dir.length() > 0) {
            dir = dir + "/" + id.substring(0,idx);
        } else
            dir = id.substring(0,idx);
        return hasAsset(id.substring(idx + 1), dir);
    }
    try {
        return Arrays.asList(context.getAssets().list(dir)).contains(id);
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }
}
1
Hostile On

I'm not sure why it works this way, but when I list "/", I get root level stuff, not things from my "assets" directory. I actually found no way to properly list my assets folder in the short time I spent trying.

The workaround I'm using is to create a "subdir" directory inside of my "assets" directory. I put all the assets that I want to access in this "subdir", and do:

String[] assetsIWant = assetMgr.list("subdir");

I don't know why "/" lists the "assets" directory itself as one of it's files, yet you don't have to specify the "assets" directory when giving list a path. Maybe someone else knows, but I hope this tip will help you out anyway.

0
David-mu On

I ve use the following code to list the file name in assets/myFolder/:

String[] fileNames =getAssets().list("myFolder");
for(String name:fileNames){
     System.out.println(name);    
}

note that the parameter in the method list does not contains "/".

0
Mahozad On

Here is a solution using Kotlin:

val assetManager = context.resources.assets
assetManager
    .list("myDirectoryNameInAssetsFolder")
    .also { Log.i("Meow", "Detected files: ${it?.joinToString()}") }
    ?.map { "myDirectoryNameInAssetsFolder/$it" }
    ?.map(assetManager::open)
    ?.map { it.bufferedReader().use(BufferedReader::readText) }
    ?.also { Log.i("Meow", "Text of each file:") }
    ?.forEach { fileText -> Log.i("Meow", fileText) }
    ?: error("Could not access/read files in assets folder")