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?
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("");
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 "/".
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.
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.
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)
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!
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;
}
}
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.
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!
Related
I have a javafx project, which contains multiple paths for images and text files :
private Image imgMan = new Image(getClass().getResource("../man.gif").toExternalForm());
FileHelper.resetScores("./bin/application/MAP/BestScores.txt");
...
When i launch from eclipse, it work normally, and access to images and files without any problem.
But when i try to export my project to a jar file, it export correctly, but it don't launch !
I try to launch it from cmd, the trace of stack said that he don't know the paths...
Caused by: java.lang.NullPointerException
at application.Client.(Client.java:31)
(line 31 in my code refer to the first line of code given in the question)
I try to create a resource folder and put all files into it, but no result.
So what is the best way to make it ?
where must i create the resource folder ?
and how to access the files into it from the code ?
Thank you
There are several thing you should check:
verify the path in your jar against the class you are looking. Your image must be there.
verify you have successfully loaded a resource because using it, eg: check if getResource returns null.
For the first point, it depends on how you build your jar:
Eclipse will by default copy class file and resources to bin unless you use m2e. If you use the Extract runnable JAR (from File > Export menu), it may ignore some resources.
If you use Maven then your images must be in src/main/resources by default.
For the second point, you should use a method that should check the resource exists before delegating to Image. While it won't change your core problem, you would have a less subtile error:
static javafx.scene.image.Image loadImage(Class<?> source, String path) {
final InputStream is = source.getResourceAsStream(path);
if (null == is) {
throw new IllegalStateException("Could not load image from " + source + " path: " + path);
}
try (is) { // Java 9 -> you may want to use InputStream is2 = is
return new javafx.scene.image.Image(is); // use is2 for Java < 9
}
}
You should also try with an absolute path (from the root of the jar, or your src/main/resources if you use maven):
Image image = loadImage(this.getClass(), "/images/man.gif");
I've tried several different things to get this to work, and none of them have. I'm trying to create a file inside of a folder in Java. The project needs to have several text files that all relate to each other, and it would be more manageable to have them all together in one folder. Ideally, this folder would be stored outside of scr/.
Here is my current code for it (I do check for file existence first):
File testFile = new File("\\appts\\Appointments" + name + ".txt");
try {
testFile.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
However, I get an IOException when I try to run the code. I have tried it how it is above, also /appts/Appointments, appts/Appointments, appts\\Appointments. I tried searching online but couldn't find anything that worked.
Edit: Here is how my project setup currently looks like:
Project_Folder
src
com
weebly
roboticplayer
appointmentbook
CLASSES
Here is how I want it to look:
Project_Folder
src
com
weebly
roboticplayer
appointmentbook
CLASSES
appts
There are two easy ways to do this:
1) Absolute path
"C:\\users\\....\\parent_folder\\filename.txt";
2) relative path,
. (Single dot) is current directory
..(double dots) is parent directory
For example, you want to create text files under project folder. And the following is your file structure.
Project_folder
src
Java_main_file.java
appts
You want to create a file under appts from Java_main_file.java
String filename = "..\\appts\\filename.txt"
Then, create your file with filename. Here is a link how to create a text file.
Note that you need to make sure the folder under which you create the files exists. If it doesn't exist, you will get an error.
You can't create a file and its non-existent parent directories in one step, but you can create the parent directories first with File.mkdirs() and then create the file.
If your using JDK7 you can use nio package.
Path path = Paths.get("C:\\appts\\Appointments");
Files.createDirectories(path);
If you want to do a path relative to your current folder:
FileSystems.getDefault().getPath("appts", "Appointments");
If you want to see the absolute pathname:
FileSystems.getDefault().getPath("appts", "Appointments").toAbsolutePath().toString();
If you need that file object:
FileSystems.getDefault().getPath("appts", "Appointments").toFile();
You can also do .toFile() after the call toAbsolutePath().
My java code lists all code files under a directory of file system, and load each file one by one:
File[] files = mDir.listFiles();
for(File f: files) {
System.out.println(f.getPath());
//load code file
System.load(f);
}
The above code logically looks good, but is not suitable for my case.
My case is that I can NOT load them in a loop one by one, because there are dependencies among those code files. I need to load the files in a specific order according to dependencies.
Say, I already know there are following files under the directory mDir which should be load in the following order:
["dFile", "xFile", "aFile", "hFile"]
and I already got the directory instance mDir .
How can I load files with above order efficiently in java?
If you already know which files you are interested in then just load them in the proper order.
If you have to see which files are available first and then load them in the specific order, then use one loop to get the names of the existing files, then process the list by picking the correct files in the correct order.
I'd suggest just setting the working directory correctly (see Changing the current working directory in Java?) and then doing
for(String fname : fileArray) {
System.load(new File(fname));
}
(where fileArray is the list of file names) or
for(String fname : fileArray) {
System.load(new File(mDir.getPath() + fname));
}
if you're intent on loading from a specific directory.
Other than that, you'd need to divine the dependencies from each file in order, or read the list of files to load from some other source (an array, another file, whatever).
I would like to list files contained into assets subdirectory called "subDir" and am using following code. However, if I set dirFrom = "" (empty), lists all folders in assets properly. However, for dirFrom = "/subDir/", doesn't work. I already tried "subDir/" and same result. Is necessary to declare permissions in manifest? Thank you.
private void copyFiles(String dirFrom, String dirTo) throws IOException {
AssetManager am = getAssets();
String fileList[] = am.list(dirFrom);
if (fileList != null)
{
for ( int i = 0;i<fileList.length;i++)
{
Log.d("",fileList[i]);
}
}
}
AssetManager.list(String) takes a "relative path within the assets".
Android / Java usually expects paths to have no '/' in the end.
Also "relative" means that there should be no '/' at the start - it could otherwise be a path in the root of your filesystem.
Using just "subDir" or "subDir/subsubDir" will work.
zapl´s answer is true, but additional info: If You want to copy the files, for example to sd card, You have to declare Your InputStream with a slash:
InputStream in = assetManager.open("subDir/"+filename);
This was something I have stumbled by copy files from a subfolder. My originally plan was to copy files directly from asset folder, this worked but gave me some IOExceptions. There were some directories "webkit","sound","images" and another one I can´t remember, inside the asset folder...but I have not seen them. This must be something Android internal that I don´t understand. But to get rid of this, I placed my files inside a subfolder. I know it is an old thread, but I put this information to this thread only to help others with similar problems.
This question has been brought up before, and I have searched many of the answers. It always ends in "You want getResourceAsStream". This is not what I am looking for.
My issue is , for a game object, I am using a folder structure to keep sprite strips rather than having one large sprite. This results in :
Media/
CharacterName/
AnimationName/
image.extension
the programming object just holds it's folder as a string, and I pass the getResource() URL to an object to fill the map of images. there can be {n} number of AnimationName/ sub directories. My error comes from this code:
dir = new File(s.toURI());
I take the directory, and call listFiles and pass the file names found to the sprite loader. Here is a code snippet:
dir = new File(s.toURI());
File[] chld = dir.listFiles();
//get a list of files in the image/character folder
for(File f:chld)
{
//get a list of the files for each dir
File[] grandChild = f.listFiles();
for(File t:grandChild)
{
String fname = t.getAbsolutePath();
System.out.println(fname);
String temp = fname;
temp = temp.substring(temp.lastIndexOf("/") + 1,temp.lastIndexOf("."));
String animName = temp.replaceAll("\\d*$", "");
int numPics = 0;
Pattern p = Pattern.compile("[0-9]+");
Matcher m = p.matcher(temp);
while(m.find()){
numPics = Integer.parseInt(m.group());
}
System.out.println("animation name: " + animName);
System.out.println("file name: " + fname);
System.out.println("number of pictures: " + numPics);
Animations.put(animName, sl.loadStripImageArray(fname, numPics));
}
}
Excuse the poor naming and temp variables, it's still being worked on.
sl is the sprite loader, and Animations is a hash map. This works fine until I package the project. I don't want to write a bunch of convoluted code that only works if I have a jar file, and not when I'm working in netbeans with the source folders.
I have considered having an application data folder, but I'd like to stay with a jar package if I can.
You do still want to use getResourceAsStream. Nothing here requires that all resources must be kept at the same folder within the JAR. You can use relative paths, or absolute paths to the root of the JAR by prefixing your path with /.
You can't make File work with resources within the JAR - even if instantiated with a URL that points to a resource contained within a JAR.
You may have to rework some other things, as the classpath is not really meant to be enumerated against (as you're currently listing files from the parent directory). It is designed to retrieve a resource by name. So one possibility (that I would recommend) is to have a "manifest" file that contains the files you want to load from each directory. (Read this file, then load the additional resources by name.)
Alternatively, if you can find the name of the JAR file you're loading from, you can create a Jarfile from it, then call its entries() method to find all of the contained resources. But even then, they aren't returned in a "tree structure", so ideally, you'd read this one, create your own tree structure from it (possibly as a series of Maps), then use it to retrieve the "directory listings" as needed.
If you are absolutely sure that the sprites are located in a jar - you could try using the JarFile class. There is a method entries. I didn't try it but it seems to return all resources located in the whole jar file. You would have to filter out which resources are in the right path.