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