Android: Как определить каталог в папке ресурсов?

Я получаю такие файлы

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

Как мы можем узнать, является ли это файл или каталог?

Я хочу пройтись по каталогам в папке активов, а затем скопировать все ее содержимое.

6 ответов

Решение

Вы можете проверить, представляет ли файл каталог, используя http://developer.android.com/reference/java/io/File.html(). Это то, что вы имели ввиду?

Я думаю, что более общее решение (в случае, если у вас есть подпапки и т. Д.) Будет выглядеть примерно так (в зависимости от решения, к которому вы добавили ссылку, я тоже добавил его):

...

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());
    }

}

Вы можете использовать метод списка AssetManager. Любой каталог в активе должен иметь как минимум один файл, пустой каталог будет игнорироваться при сборке приложения. Итак, чтобы определить, является ли какой-либо путь каталогом, используйте вот так:

    AssetManager manager = activity.getAssets();
    try{
        String[] files = manager.list(path);
        if (files.length > 0){
            //directory
        }
        else{
            //file
        }
    }
    catch (Exception e){
        //not exists.
    }

Я обнаружил этот вариант:

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
}

Это быстрее, чем.list()

Ужасающая правда заключается в том, что, несмотря на то, что его спросили почти 10 лет назад, на сегодняшний день ни один простой, элегантный, широко аплодируемый метод определения того, является ли элемент в массиве, возвращаемом AssetManager.list(), является файлом или каталогом..

Так, например, если каталог ресурсов содержит тысячу элементов, то, по-видимому, необходима тысяча операций ввода-вывода для изоляции каталогов.

Также для любого элемента не существует никакого собственного метода для получения его родительского каталога - жизненно важного для чего-то сложного, например, браузера / средства выбора ресурсов - где вы могли бы в конечном итоге увидеть какой-то серьезно уродливый код.

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

Боковой подход, который сработал для меня, заключался в предположении, что любой элемент без точки (.) В его имени является каталогом. Если позднее предположение окажется неверным, его легко исправить.

Файлы активов обычно существуют потому, что вы их туда помещаете. Разверните соглашения об именах, которые различают каталоги и файлы.

Вы также можете попробовать это, у меня это работает, так как вы не можете полагаться исключительно на.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;
        }
    }
}

Еще один способ полагаться на исключения:

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);
    }
}

а затем просто вызовите checkAssets("someFolder", getAssets()); или checkAssets("", getAssets()); если вы хотите проверить папку корневых активов. Но имейте в виду, что папка корневых ресурсов содержит также другие каталоги / файлы (например, webkit, изображения и т. Д.)

В вашем конкретном случае, поскольку вы получили файлы через list, вы уже знаете, что эти имена существуют. Это сильно упрощает задачу. Вы можете просто использовать это:

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;
    }
}

С другой стороны, если вам нужно общее решение для определения того, существует ли определенный путь и является ли он папкой, вы можете использовать это:

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.
    }
}

Я написал их для веб-сервера, поэтому не мог делать предположений о форме входного пути. Но это можно немного упростить, если у вас есть определенные правила. Этот код возвращается немедленно, как только становится определенным тип актива, чтобы избежать дополнительных накладных расходов на обработку.

Вы можете начать с Android-файла

Другие вопросы по тегам