【发布时间】:2011-09-10 16:06:49
【问题描述】:
我正在检索这样的文件
String[] files = assetFiles.list("EngagiaDroid");
我们如何知道它是文件还是目录?
我想遍历 assets 文件夹中的目录,然后复制其所有内容。
【问题讨论】:
我正在检索这样的文件
String[] files = assetFiles.list("EngagiaDroid");
我们如何知道它是文件还是目录?
我想遍历 assets 文件夹中的目录,然后复制其所有内容。
【问题讨论】:
您可以使用http://developer.android.com/reference/java/io/File.html#isDirectory() 检查文件是否代表目录。是这个意思吗?
【讨论】:
你可以从Android File开始
【讨论】:
我认为更通用的解决方案(如果您有子文件夹等)将是这样的(基于您链接到的解决方案,我也已将其添加到那里):
...
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());
}
}
【讨论】:
我发现了这个变种:
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() 更快
【讨论】:
另一种依赖异常的方式:
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、图像等)
【讨论】:
您可以使用 AssetManager 的列表方法。 资产中的任何目录至少应该有一个文件,构建应用程序时将忽略空目录。 因此,要确定某个路径是否是目录,请像这样使用:
AssetManager manager = activity.getAssets();
try {
String[] files = manager.list(path);
if (files.length > 0) {
//directory
} else {
//file
}
} catch (Exception e) {
//not exists.
}
【讨论】:
在您的特定情况下,由于您通过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.
}
}
我为 Web 服务器编写了这些,因此我无法对输入路径的形状做出假设。但是,如果您设置了一些规则,则可以稍微简化一下。一旦确定资产的类型,此代码会立即返回,以避免额外的处理开销。
【讨论】:
令人震惊的事实是,尽管在近 10 年前被问到,没有简单、优雅、广受赞誉的方法来确定 AssetManager.list() 返回的数组中的元素是文件还是迄今为止,任何答案都提供了一个目录。
因此,例如,如果资产目录包含一千个元素,那么似乎需要一千个 I/O 操作来隔离目录。
对于任何元素,也不存在任何用于获取其父目录的本机方法 - 对于像资产 Browser / Picker 这样复杂的东西至关重要 - 您最终可能会看到一些非常丑陋的代码。
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;
}
}
}
【讨论】: