8

I'm retrieving files like this

String[] files = assetFiles.list("EngagiaDroid"); 

How can we know whether it is a file or is a directory?

I want to loop through the directories in the assets folder then copy all of its contents.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Kris
  • 3,709
  • 15
  • 50
  • 66

9 Answers9

5

I think a more general solution (in case you have subfolders etc.) would be something like this (based on the solution you linked to, I've added it there too):

...

copyFileOrDir("myrootdir");

...

private void copyFileOrDir(String path) {
    AssetManager assetManager = this.getAssets();
    String assets[] = null;
    try {
        assets = assetManager.list(path);
        if (assets.length == 0) {
            copyFile(path);
        } else {
            String fullPath = "/data/data/" + this.getPackageName() + "/" + path;
            File dir = new File(fullPath);
            if (!dir.exists())
                dir.mkdir();
            for (int i = 0; i < assets.length; ++i) {
                copyFileOrDir(path + "/" + assets[i]);
            }
        }
    } catch (IOException ex) {
        Log.e("tag", "I/O Exception", ex);
    }
}

private void copyFile(String filename) {
    AssetManager assetManager = this.getAssets();

    InputStream in = null;
    OutputStream out = null;
    try {
        in = assetManager.open(filename);
        String newFileName = "/data/data/" + this.getPackageName() + "/" + filename;
        out = new FileOutputStream(newFileName);

        byte[] buffer = new byte[1024];
        int read;
        while ((read = in.read(buffer)) != -1) {
            out.write(buffer, 0, read);
        }
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
    } catch (Exception e) {
        Log.e("tag", e.getMessage());
    }

}
DannyA
  • 1,571
  • 2
  • 17
  • 28
4

You may use list method of AssetManager. Any directory in asset should have one file at least, empty directory will be ignored when building your application. So, to determine if some path is directory, use like this:

AssetManager manager = activity.getAssets();
try {
    String[] files = manager.list(path);
    if (files.length > 0) {
        //directory
    } else {
        //file
    }
} catch (Exception e) {
    //not exists.
}
alexrnov
  • 2,346
  • 3
  • 18
  • 34
dexiang
  • 1,345
  • 16
  • 23
2

I've discovered this variant:

try {
    AssetFileDescriptor desc = getAssets().openFd(path);  // Always throws exception: for directories and for files
    desc.close();  // Never executes
} catch (Exception e) {
    exception_message = e.toString();
}

if (exception_message.endsWith(path)) {  // Exception for directory and for file has different message
    // Directory
} else {
    // File
}

It's a more faster as .list()

Vladyslav Savchenko
  • 1,282
  • 13
  • 10
  • This will not throw for uncompressed files, so it will not always throw. But this can be easily fixed. On the other hand, relying on exception messages doesn't look nice to me. They could possibly change. – Raslanove Jul 29 '20 at 23:54
2

The appalling truth is that despite being asked nearly 10 years ago, no simple, elegant, roundly applauded method of determining whether an element in the array returned by AssetManager.list() is a file or a directory has been offered by any answer to date.

So, for example, if an asset directory contains a thousand elements, then seemingly a thousand I/O operations are necessary to isolate the directories.

Nor, for any element, does any native method exist for obtaining its parent directory - vital for something complex like an assets Browser / Picker - where you could end up looking at some seriously ugly code.

boolean isAssetDirectory = !elementName.contains(".");

The lateral approach that worked for me was to assume that any element without a dot (.) in its name was a directory. If the assumption is later proved wrong it can be easily rectified.

Asset files generally exist because you put them there. Deploy naming conventions that distinguish between directories and files.

Bad Loser
  • 3,065
  • 1
  • 19
  • 31
0

Another way relying on exceptions:

private void checkAssets(String path, AssetManager assetManager) {
    String TAG = "CheckAssets";
    String[] fileList;
    String text = "";
    if (assetManager != null) {
        try {
            fileList = assetManager.list(path);
        } catch (IOException e) {
            Log.e(TAG, "Invalid directory path " + path);
            return;
        }
    } else {
        fileList = new File(path).list();
    }

    if (fileList != null && fileList.length > 0) {
        for (String pathInFolder : fileList) {
            File absolutePath = new File(path, pathInFolder);

            boolean isDirectory = true;
            try {
                if (assetManager.open(absolutePath.getPath()) != null) {
                    isDirectory = false;
                }
            } catch (IOException ioe) {
                isDirectory = true;
            }

            text = absolutePath.getAbsolutePath() + (isDirectory ? " is Dir" : " is File");
            Log.d(TAG, text);
            if (isDirectory) {
                checkAssets(absolutePath.getPath(), assetManager);
            }
        }
    } else {
        Log.e(TAG, "Invalid directory path " + path);
    }
}

and then just call checkAssets("someFolder", getAssets()); or checkAssets("", getAssets()); if you want to check the root assets folder. But be aware that the root assets folder contains also other directories/files (Eg. webkit, images, etc.)

Cosmin
  • 201
  • 2
  • 8
0

In your particular case, since you retrieved the files through list, you already know that these names exist. This simplifies the problem a lot. You can simply use this:

public static boolean isAssetAFolder(AssetManager assetManager, String assetPath) throws IOException {

    // Attempt opening as a file,
    try {
        InputStream inputStream = assetManager.open(assetPath); inputStream.close();
        return false; // A file indeed.
    } catch (FileNotFoundException e) {
        // We already know this name exists. This is a folder.
        return true;
    }
}

On the other hand, if you need a generic solution to detect if a certain path both exists and is a folder, you can use this:

public static boolean isAssetAFolder(AssetManager assetManager, String assetPath) throws IOException {

    // Attempt opening as a file,
    try {
        InputStream inputStream = assetManager.open(assetPath); inputStream.close();
        return false; // A file indeed.
    } catch (FileNotFoundException e) {
        // This could be a folder, or this path doesn't exist at all. Further checking needed,
        return assetPathExists(assetManager, assetPath);
    }
}

// If you are checking a file name "icon.png" inside your assets folder, the assetPath should be "icon.png".
public static boolean assetPathExists(AssetManager assetManager, String assetPath) throws IOException {

    // Assume that "" exists by default,
    if (assetPath.isEmpty()) return true;

    // Reject paths that point outside the assets folder,
    if (assetPath.startsWith("..") || assetPath.startsWith("/")) return false;

    // For other file/folder paths, we'll search the parent folder,
    File fileOrFolder = new File(assetPath);
    String parent = ((parent=fileOrFolder.getParent()) != null) ? parent : ""; // Handle null parents.
    if (!Arrays.asList(assetManager.list(parent)).contains(fileOrFolder.getName())) return false;

    // Getting this far means that the specified assetPath indeed exists. However, we didn't handle files
    // with trailing "/". For instance, "icon.png/" shouldn't be considered existing although "icon.png"
    // does.

    // If the path doesn't end with a "/", we are safe,
    if (!assetPath.endsWith("/")) return true;

    // Remove the trailing slash,
    assetPath = assetPath.substring(0, assetPath.length()-1);

    // Attempt opening as a file,
    try {
        InputStream inputStream = assetManager.open(assetPath); inputStream.close();
        return false; // It's indeed a file (like "icon.png"). "icon.png/" shouldn't exist.
    } catch (FileNotFoundException e) {
        return true; // This is a folder that exists.
    }
}

I wrote these for a web server, so I couldn't make assumptions about the shape of the input path. But it can be simplified a bit if you have some rules set. This code returns immediately once it becomes certain of the type of the asset, to avoid the extra processing overhead.

Raslanove
  • 649
  • 9
  • 16
0

You can also try this, it works for me, since you cannot rely solely on .list()

public static boolean isDirectory(Context context, String path) throws IOException {
    //If list returns any entries, than the path is a directory
    String[] files = context.getAssets().list(path);
    if (files != null && files.length > 0) {
        return true;
    } else {
        try {
            //If we can open a stream then the path leads to a file
            context.getAssets().open(path);
            return false;
        } catch (Exception ex) {
            //.open() throws exception if it's a directory that you're passing as a parameter
            return true;
        }
    }
}
-1

You can start from Android File

Muhammad Zeeshan
  • 8,722
  • 10
  • 45
  • 55
  • 2
    thanks for your response. but i don't think some funcitons like isDirectory is not working in the assets folder – Kris Jun 08 '11 at 08:02
-2

You can check if a File represents a directory using http://developer.android.com/reference/java/io/File.html#isDirectory(). Is that what you mean?

Asahi
  • 13,378
  • 12
  • 67
  • 87
  • 2
    thanks for you response. Yes but when I tried it, it's not working when the file is in your assets folder. Maybe because files are included in the package. – Kris Jun 08 '11 at 08:01
  • I end up using [this code](http://stackoverflow.com/questions/4447477/android-how-to-copy-files-in-assets-to-sdcard). I execute this code times the number of my folders. :) – Kris Jun 16 '11 at 10:14
  • AssetManager does not return File objects, therefore the File API is not applicable. – Dustin Pfannenstiel Oct 03 '18 at 14:55