简体   繁体   English

Android:如何检测资产文件夹中的目录?

[英]Android: How to detect a directory in the assets folder?

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.我想遍历资产文件夹中的目录,然后复制其所有内容。

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

}

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()这是一个更快的 as.list()

You may use list method of AssetManager.您可以使用 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.
}

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());然后只需调用checkAssets("someFolder", getAssets()); or checkAssets("", getAssets());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.)但请注意,根资产文件夹还包含其他目录/文件(例如 webkit、图像等)

In your particular case, since you retrieved the files through list , you already know that these names exist.在您的特定情况下,由于您通过list检索了文件,因此您已经知道这些名称存在。 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.我为 web 服务器编写了这些,所以我无法对输入路径的形状做出假设。 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.一旦确定资产的类型,此代码会立即返回,以避免额外的处理开销。

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.令人震惊的事实是,尽管在近 10 年前被问到,迄今为止,任何答案都没有提供简单、优雅、广受赞誉的方法来确定AssetManager.list()返回的数组中的元素是文件还是目录.

So, for example, if an asset directory contains a thousand elements, then seemingly a thousand I/O operations are necessary to isolate the directories.因此,例如,如果资产目录包含一千个元素,那么似乎需要一千个 I/O 操作来隔离目录。

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.部署区分目录和文件的命名约定。

You can also try this, it works for me, since you cannot rely solely on.list()你也可以试试这个,它对我有用,因为你不能仅仅依赖 .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;
        }
    }
}

You can start from Android File您可以从Android 文件开始

You can check if a File represents a directory using http://developer.android.com/reference/java/io/File.html#isDirectory ().您可以使用http://developer.android.com/reference/java/io/File.html#isDirectory () 检查文件是否代表目录。 Is that what you mean?你是这个意思吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM