Reputation: 27
I have spent ages trying to find out how to get the directory of the resources file (res/raw
) for months now... I just can't find out how to do it...
I'm attempting to get the directory of res/raw
so that I can use listFiles()
to make an array containing all the files in the raw folder so that I may get the file names and sort which files I will use or not through there names (as I can then access them through R.raw.concat(fileIwantToAccess)
) but I need to be able to read all the files in the folder so that I can decide which I use
Is there an easier way to tell Android, that I would like the contents of this folder?
btw, Ive tried using
String directoryName = Soundboard.this.getFilesDir().getParent();
but it returns the path: /data/data/com.soundboard
which has the two sub directories: "lib" and "files", if I then concat both directories to directoryName before I make the File it returns nothing when I use listFiles();
but not null, it returns []
Please help... I am hopelessly lost
Upvotes: 0
Views: 949
Reputation: 91
@ Michael,
We cannot comment on each other’s posts because we are too new. Welcome, aboard.
To answer your question, you CAN dynamically query which audio files are available. You just can’t do so by using the /res/raw
directory. You must use the /assets
directory for this.
First, I would like to clarify that /res/raw
and /assets
are both legitimate places to package files with an application. They are used for different purposes, however, and each has a different significance. So, what is the significance of each location, and when (or why) should you place files in each location?
Well, let's consider the /res/raw
location first. Placing a file in /res/raw
makes the file a Resource. With Android, Resource means something very specific; it doesn't just mean "something available to use". Rather, a Resource is something that could potentially have multiple versions that are "swappable" at runtime. The “active” version will depend on the application’s context (environment). For example, several different versions of the same “Resource” might exist for different locales and languages, for different form factors (screen sizes), for different orientations of the device, or even for different visual themes of the application!
Resources are accessed through Resource IDs, which are analogous to pointers; they refer to the different variants indirectly. For example, I might package 3 different versions of an icon with my application, each appropriate for a different screen density. In my source code, though, I don’t refer to each version individually; I simply have one resource ID - something like R.drawable.icon
- that refers to "the icon". When the device is running on a high-density screen, R.drawable.icon
“points” to the hi-density version of the icon; and on a low-density device, R.drawable.icon
“points” to the low-density version.
Now, the mechanisms used to actually resolve the Resource name is beyond the scope of this post. But here is the upshot: each variant has a different path, but the Resource ID is the same for all variants! Consequently, we must refer to resources via ID only. We can’t refer to resources by path, and we can’t even list the paths out – that would defeat the purpose of Resources to begin with. And we shouldn’t need to. We should always know which resources we need, we just know which variant we'll get, and we don't care (at least, we shouldn’t).
This is why you are haveing such trouble querying the resources in /res/raw
, or even getting to the directory itself. Those functions are contrary to the concept of Resources. By definition, you always know what Resource you want ahead of time - and the Resource ID that goes with it.
So, what if you don’t know what you want, and therefore want figure out what’s available? Well, that’s the purpose of the /assets location. Note
that /assets
is not part of the resource hierarchy. And therein lies the distinction between the /res/raw
and /assets
: things in /assets
are not resources.
Since things placed in /assets
are not resources, they do not have Resource IDs. So you must refer to them by their path. In fact, since you
don’t know where the /assets
folder itself is located, you must refer to them by their relative path. Enter AssetManager. AssetManager (a) knows how to find the your application’s /assets
folder, (b) how to list files and folders under the /assets
folder, and (c) how to open files and folders under the /assets
folder. To see how this is done, please review the docs for the AssetManager class, and post again if you need further guidance.
So, in summary: if you have a file that’s a Resource, then put it in /res/raw
, and access it via it’s resource ID. If the file is not a resource, then put it somewhere in the /assets
folder, and access it via its path.
For more information on resources, see the Application Resources page in the Android Developers Guide
Does this make things clearer?
Upvotes: 1
Reputation: 91
Perhaps you should consider using asset files instead of raw resources.
Raw resources are intended to be referenced through resource IDs, not via path. For example, if you place the file foo.txt in /res/raw
, then the file can be accessed via the resource ID R.raw.foo
. Presumably, then, raw resources only used when the name of the resource is known at compile time.
Files places in /assets
, On the other hand, do not generate resource IDs. They are intended to be referenced by path; in fact, you must access them via their path using AssetManager. Thus, /assets
is a better choice if you don't know the name of the resource/file at compile time, but "will know it when you see it". AssetManager even has a method for listing files at a particular path. For example, if you wanted a list of files /assets/foo
, you could try:
try {
AssetManager am = getAssets();
String files[] = am.list("foo");
// process the files
}
catch (IOException ioe) {
// do something wise
}
Now, expanding on AndroidMirza’s points, if you know the set of possible resources at compile time, but want to access these resources selectively at runtime, then you can use the resources names to dynamically generate their ids. This is what AndroidMirza was suggesting. Consider, for example:
// names of resources we actually want to use
String desiredResources[] = { "foo", "bar" };
for (String rName : desiredResources) {
// dynamically generate the resource's ID from its name
int rID =
getResources().getIdentifier(rName, "raw",
this.getPackageName());
// open the resource using the generated ID
InputStream rStream = getResources().openRawResource(rID);
}
In conclusion, please recall that resources have special significance in Android. Specifically, resources are used to dynamically adapt the application for context (localization, different hardware profiles, specific configurations, etc). While raw resources and asset files are both used to access files as a byte stream, they have different intents. Files placed in /res/raw are intended to be actual resources: alternative versions could exist for different contexts. Since these resources could resolve to different paths based on context, they are accessed indirectly, via their resource id. Files placed in /assets, however, have no "resource" significance: they merely contain data to be used by the application. Since their locations are not context-dependent, then can be accessed directly via their path.
I hope this helps.
Upvotes: 0
Reputation: 18489
You can try like this as follows:
resId=getResources().getIdentifier(
"name of your file inside raw folder",
"raw",
this.getPackageName()
);
Upvotes: 0