Hej,
I have some data shipped out with the app which shall be copied on the external storage. It's nested in a couple of subfolders and I'd like to copy the whole structure.
I'm having a hard time getting a File object for any ressource in /assets
. But I think I'm depended on that 'cause I need something like File.isDirectory() to determine if I have to start copying or dive deeper into the system.
My first approach was using Assets Manager but it seems that class is not providing the information I need. The most promising why was to obtain an AssetFileDescriptor
and go down to a [FileDescriptor][2]
. However non of them seems to have a isDirectory
-method.
So my other approach is straight forward: Creating a File Object and be happy. However it seems like I'm running in this problem of lacking a proper path to instance the file object. I'm aware of file://android_asset
but it doesn't seem to work for the file
constructor.
My last idea would to utilise the InputStream (which I need for copying anyway) and somehow filter the byte for a significant bit which indicates this resource to be a directory. That's a pretty hacky solution and probably right in the hell of ineffectiveness but I don't see another way to get around that.
I had the same problem. At some point I realized that list()
is really slow (50ms on every call), so i'm using a different approach now:
I have an (eclipse) ant-builder which creates an index-file everytime my asset-folder changes. The file just contains one file-name per line, so directories are listed implicitely (if they are not empty).
The Builder:
<?xml version="1.0"?>
<project default="createAssetIndex">
<target name="createAssetIndex">
<fileset id="assets.fileset" dir="assets/" includes="**"
excludes="asset.index" />
<pathconvert pathsep="${line.separator}" property="assets"
refid="assets.fileset">
<mapper>
<globmapper from="${basedir}/assets/*" to="*"
handledirsep="yes" />
</mapper>
</pathconvert>
<echo file="assets/asset.index">${assets}</echo>
</target>
</project>
The class which loads asset.index
into a List of Strings, so you can do arbitrary stuff with it, fast:
import android.content.ContextWrapper;
import com.google.common.collect.ImmutableList;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* uses asset.index file (which is pregenerated) since asset-list()s take very long
*
*/
public final class AssetIndex {
//~ Static fields/initializers -------------------------------------------------------------------------------------
private static final Logger L = LoggerFactory.getLogger(AssetIndex.class);
//~ Instance fields ------------------------------------------------------------------------------------------------
private final ImmutableList<String> files;
//~ Constructors ---------------------------------------------------------------------------------------------------
public AssetIndex(final ContextWrapper contextWrapper) {
ImmutableList.Builder<String> ib = ImmutableList.builder();
L.debug("creating index from assets");
InputStream in = null;
Scanner scanner = null;
try {
in = contextWrapper.getAssets().open("asset.index");
scanner = new Scanner(new BufferedInputStream(in));
while (scanner.hasNextLine()) {
ib.add(scanner.nextLine());
}
scanner.close();
in.close();
} catch (final IOException e) {
L.error(e.getMessage(), e);
} finally {
if (scanner != null) {
scanner.close();
}
if (in != null) {
try {
in.close();
} catch (final IOException e) {
L.error(e.getMessage(), e);
}
}
}
this.files = ib.build();
}
//~ Methods --------------------------------------------------------------------------------------------------------
/* returns the number of files in a directory */
public int numFiles(final String dir) {
String directory = dir;
if (directory.endsWith(File.separator)) {
directory = directory.substring(0, directory.length() - 1);
}
int num = 0;
for (final String file : this.files) {
if (file.startsWith(directory)) {
String rest = file.substring(directory.length());
if (rest.charAt(0) == File.separatorChar) {
if (rest.indexOf(File.separator, 1) == -1) {
num = num + 1;
}
}
}
}
return num;
}
}
In my specific case, regular files have a name like filename.ext, while directories only have a name, without extension, and their name never contains the "." (dot) character. So a regular file can be distinguished from a directory by testing its name as follows:
filename.contains(".")
If this your case too, the same solution should work for you.
list() on AssetManager will probably give a null / zero length array / IOException if you try to get a list on a file, but a valid response on a directory.
But otherwise it should be file:///android_asset (with 3 /)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With