Android seems to make life pretty easy for loading resources of certain types. Once I leave the beaten path a little bit, it seems less helpful. I can load in images, sounds and other objects from the assets folder if and only if they are of certain types. If I try to load a binary file of my own format, I get a less than helpful 'file not found' exception, even though listing the directory shows that it is clearly there.
I've tried using the following methods to read a binary file of a custom format from the assets directory:
File jfile = new File("file://android_asset/"+filename); //tried to get the URI of the assets folder
JarFile file = new JarFile("assets/"+filename); //tried assuming the assets folder is root
fd = am.openNonAssetFd( filename); //tried getting my file as an non asset in the assets folder (n.b. it is definitely there)
fs = am.open(filename, AssetManager.ACCESS_BUFFER); //tried loading it as an asset
I'm thinking that there's something fundamental about android file I/O that I don't understand yet. The documentation for asset management seems incomplete and there must be some reason for deliberately making this unintuitive (something to do with security?). So, what's the fool proof, canonical way of loading a binary file of my own format within an android app?
UPDATE:
I tried file:///android_asset/ but still no joy.
String fullfilename = "file:///android_asset/"+filename;
File jfile = new File(fullfilename);
if (jfile.exists())
{
return new FileInputStream(jfile);
}
else
{
return null; //the file does exist but it always says it doesn't.
}
Are there any permissions for the file or in the project manifest that I need?
Thanks
I think the best way to load a file from the Assets folder would be to use AssetManager.open(String filename) - this gives you back an InputStream which you can then wrap in a BufferedInputStream and otherwise call read() to get the bytes. This would work regardless of the file type. What kind of problems have you had with this approach specifically?
I think you have left out the slash as in
File jfile = new File("file:///android_asset/"+filename);
There's three forward slashes, not two. :)
For me the solution was to uninistall the application, clean the project in Eclipse and run it again. The problem was Android couldn't find the new files I put in the asset folder.
I ended up reading this question so I hope this can be helpful to someone else.
Related
If I want to access a directory, I would to the following:
File f = new File(getFilesDir()+"/name");
And then, if f is a directory, I can iterate through the files and do a lot of things.
Can I do the same with the drawable/raw folder? I know how to get the id of a file using the name or the name using the id, but I am not sure how can I use drawable as a directory. I also need to use FileInputStream on some files, so I need a file type, not an id or a name.
I found some 'some what' related questions, like this one: Retrieving all Drawable resources from Resources object
But my problem is a bit different. I know how to get a resource in this way. By getting the id you can do lots of things, but as far as I know, you can not use FileInputStream. That's what I need: the possibility to use FileInputStream on a resource that is inside a project folder(drawable or raw).
Can I do the same with the drawable/raw folder?
Not really.
the possibility to use FileInputStream on a resource that is inside a project folder(drawable or raw)
Resources are not files. You cannot get a FileInputStream on them.
For raw resources, you can call openRawResource() on a Resources object to get an InputStream, though.
I currently started programming a board game playground which can load different games. I store these games in file named config.txt, but I am having trouble accessing it. Firstly, I started with my favourite file approach:
String fileAddress = "./resources/config.txt";
fis = new FileInputStream(fileAddress);
reader = new BufferedReader(new InputStreamReader(fis));
But then when I built .jar file, it stopped working. For obvious reasons. So I found myself looking around and I found about recommendation to use getResourceAsStream(String s) method. So I changed my code to following way:
String fileAddress = "./resources/config.txt";
InputStream toReturn=null;
toReturn = this.getClass().getClassLoader().getResourceAsStream(fileAddress);
But here I got stuck. No matter how I tweak the fileAddress (tried ./config.txt ./resources/config.txt ./resources/boardgames/config.txt and ./resources/boardgames/config.txt) and both using or omitting getClassLoader(), the result of toReturn just always equals NULL and ends up throwing NullPointerException very soon.
Location of required file follows. As I do not have enough reputation, I will have to ASCII art the file hierarchy. Both config.txt are valid targets.
On File System:
Boardgames
src
cache
classes
resources
boardgames
config.txt
imgs
config.txt
Inside Jar File
BoardGames.jar
boardgames
<class files>
config.txt
imgs
META-INF
config.txt
Therefore I would need an assistance with repairing the code so that it would read the file properly. If you could include tips how to get ImageIcon from the .png files located in subfolders imgs, since I reckon I will run into similar problem once I get past the initialization phase via config.txt.
Thank you for all your help.
thanks to #EJP and #immibis for all help.
this.getClass().getResourceAsStream("boardgames/config.txt");
was the solution that finally got me running
I've built a Java application that loads an image at runtime. The location of the image is fixed relative to the project.
I would like to be able to run the program from both within Eclipse and the command line and for it to load the image correctly. However, I can only do one or the other but not both. This seems like such a trivial thing to want to do but I can't find out how to do it.
The project is set up so that it creates a bin directory for the output and puts the image in a resources sub-folder. This is fine when running from the command line as I can write my code to look in that sub folder for the file.
But when I run the program from within eclipse the current working directory is different.
What am I missing?
TIA
Update - adding some code
This is what I had originally:
BufferedImage awtImage = ImageIO.read(new File(System.getProperty("user.dir") + "/resources/image-name.png"));
Following the advice in the comments I am trying to use getResourceAsStream but I don't know what to pass to the File constructor.
InputStream temp = MyClass.class.getResourceAsStream("resources/image-name.png");
BufferedImage awtImage = ImageIO.read(new File(???));
The resource is being found because temp is not null.
I think there's 2 solutions.
1) you specify an absolute path
2) your image is in the classpath so you could load it via :
YouClass.class.getResourceAsStream("YourImg.png");
The working directory, if that's really what you mean, is not a great place to load an image from. It appears that you have an image that you would distribute with your finished program so that the program could use it. In that case, I suggest that you use Class.getResourceAsStream(), and put the image in the directory with (or near) that class.
EDIT:
Here is code I used in one of my programs for a similar purpose:
ImageIcon expandedIcon = null;
// ...
expandedIcon = new ImageIcon(TreeIcon.class.getResource("images/Expanded.png"));
The ImageIcon class is part of Swing; I don't know if you're using that, but this should serve to show you the idea. The getResource() method takes a URL; again, you might need something a little different. But this shows the pathname relative to the path of the class on which the method is called, so if TreeIcon is in x/y/z/icons, the PNG file needs to be in x/y/z/icons/images, wherever that is on that computer.
TreeIcon is a class of mine, and its internals will not help you, so I'm not posting them. All it's doing here is providing a location for the PNG file I'm loading into an ImageIcon instance.
In addition to working on a disk with a directory structure, this also works in a jar file (which is a common way to distribute a java program or library). The jar file is just a zip file, and each file in the jar/zip file has its directory associated with it, so the image can be in the jar in the correct directory just as the java classes are in their directories.
getResourceAsStream() returns a stream; if you want to use that byte stream to load as an image, find a class that converts an stream to something your image class can use as a constructor or in a load method and hook them up. This is a common thing to have to figure out with Java i/o, unfortunately there is no cookbook way to do it across all images and situations, so we can't just tell you what it is.
EDIT 2:
As from the comment, try:
ImageIO.read(new File(MyClass.class.getResource("resources/image-name.png");
I set up my Eclipse projects like this.
The input directory is added to the classpath (JavaBuildPath in Eclipse).
Finally, you access the image and / or text files like this.
private BufferedImage getIconImage() {
try {
return ImageIO.read(getClass().getResourceAsStream(
"/StockMarket.png"));
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
My resources folder inside my jar includes a directory with several binary files. I am attempting to use this code to extract them:
try(InputStream is = ExternalHTMLThumbnail.class.getResourceAsStream("/wkhtmltoimage")) {
Files.copy(is, Paths.get("/home/dan/wkhtmltoimage");
}
This is throwing the error
java.nio.file.NoSuchFileException: /home/dan/wkhtmltoimage
Which comes from
if (errno() == UnixConstants.ENOENT)
return new NoSuchFileException(file, other, null);
in UnixException.java. Even though in Files.java the correct options are passed:
ostream = newOutputStream(target, StandardOpenOption.CREATE_NEW,
StandardOpenOption.WRITE);
from Files.copy. Of course there's not! That's why I'm trying to make it. I don't yet understand Path and Files enough to do this right. What's the best way to extract the directory and all its contents?
Confused because the docs for Files.copy claims
By default, the copy fails if the target file already exists or is a symbolic link
(Apparently it fails if the target file doesn't exist as well?)
And lists the possible exceptions, and NoSuchFileException is not one of them.
If you're using Guava:
URL url = Resources.getResource(ExternalHTMLThumbnail.class, "wkhtmltoimage");
byte[] bytes = Resources.toByteArray(url);
Files.write(bytes, new File("/my/path/myFile"));
You could of course just chain that all into one line; I declared the variables to make it more readable.
The file that does not exist may actually be the directory you're trying to create the file in.
/home/dan/wkhtmltoimage
Does /home/dan exist? Probably not if you're on a Mac.
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.