确定Android资产条目是文件还是目录

13

你好,

我有一些数据随应用程序一起发送,需要将其复制到外部存储器中。它被嵌套在几个子文件夹中,我想复制整个结构。

我很难为`/assets`中的任何资源获得File对象。但是我认为我依赖于这个因为我需要像`File.isDirectory()`这样的东西来确定是开始复制还是深入系统。

我的第一个方法是使用Assets Manager,但是似乎该类没有提供我所需的信息。最有希望的方法是获得一个`AssetFileDescriptor`并转换为`[FileDescriptor][2]`。 然而,它们都似乎没有一个`isDirectory`方法。

所以我的其他方法很直接:创建File对象并愉快地使用它。 但是看起来我遇到了缺乏正确路径来实例化文件对象的问题。我知道`file://android_asset`,但它似乎对`file`构造函数无效。

我的最后一个想法是利用InputStream(我需要它进行复制),并以某种方式过滤字节以获取指示此资源为目录的有效位。 这是一个相当hacky的解决方案,并且可能完全没有效果,但我看不到另一个解决办法。


您还可以查看 https://dev59.com/fVjUa4cB1Zd3GeqPNQV1#46827944,该链接结合了 AssetManager.list()AssetManager.open() 两种方法。 - Cosmin
3个回答

13

我也遇到了同样的问题。后来发现每次调用list()都很慢(需要50ms),所以现在我采用了不同的方法:

我有一个(eclipse)ant-builder,每当我的资产文件夹更改时就会创建一个索引文件。该文件只包含每行一个文件名,因此目录被隐式列出(如果它们不为空)。

这个Builder:

<?xml version="1.0"?>
<project default="createAssetIndex">
    <target name="createAssetIndex">
        <fileset id="assets.fileset" dir="assets/" includes="**"
            excludes="asset.index" />
        <pathconvert pathsep="${line.separator}" property="assets"
            refid="assets.fileset">
            <mapper>
                <globmapper from="${basedir}/assets/*" to="*"
                    handledirsep="yes" />
            </mapper>
        </pathconvert>
        <echo file="assets/asset.index">${assets}</echo>
    </target>
</project>

这个类将asset.index加载到一个字符串列表中,让你可以快速地进行各种任意的操作:

import android.content.ContextWrapper;

import com.google.common.collect.ImmutableList;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import java.util.Scanner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * uses asset.index file (which is pregenerated) since asset-list()s take very long
 *
 */
public final class AssetIndex {

    //~ Static fields/initializers -------------------------------------------------------------------------------------

    private static final Logger L = LoggerFactory.getLogger(AssetIndex.class);

    //~ Instance fields ------------------------------------------------------------------------------------------------

    private final ImmutableList<String> files;

    //~ Constructors ---------------------------------------------------------------------------------------------------

    public AssetIndex(final ContextWrapper contextWrapper) {

        ImmutableList.Builder<String> ib = ImmutableList.builder();

        L.debug("creating index from assets");

        InputStream in  = null;
        Scanner scanner = null;
        try {
            in          = contextWrapper.getAssets().open("asset.index");
            scanner     = new Scanner(new BufferedInputStream(in));

            while (scanner.hasNextLine()) {
                ib.add(scanner.nextLine());
            }

            scanner.close();
            in.close();

        } catch (final IOException e) {
            L.error(e.getMessage(), e);
        } finally {
            if (scanner != null) {
                scanner.close();
            }
            if (in != null) {
                try {
                    in.close();
                } catch (final IOException e) {
                    L.error(e.getMessage(), e);
                }
            }
        }

        this.files = ib.build();
    }

    //~ Methods --------------------------------------------------------------------------------------------------------

    /* returns the number of files in a directory */
    public int numFiles(final String dir) {

        String directory = dir;
        if (directory.endsWith(File.separator)) {
            directory = directory.substring(0, directory.length() - 1);
        }

        int num = 0;
        for (final String file : this.files) {
            if (file.startsWith(directory)) {

                String rest = file.substring(directory.length());
                if (rest.charAt(0) == File.separatorChar) {
                    if (rest.indexOf(File.separator, 1) == -1) {
                        num = num + 1;
                    }
                }
            }
        }

        return num;
    }
}

1
这非常好而且有用,但我需要在pathconvert中添加'dirsep =“/”'。否则,在Windoze上Java会说路径分隔符是'',这在Android资产管理器中不起作用。 - Flynny75
1
对于那些在使用Gradle时遇到困难的人,请参考https://dev59.com/93bZa4cB1Zd3GeqPE17y - Petrus Repo
我正在使用Gradle,是否有使用Gradle的解决方案? - wukong

4

list() 在 AssetManager 上如果你尝试获取文件的列表,可能会返回 null / 长度为零的数组 / IOException,但在目录上则会返回有效响应。

但除此之外,应该是 file:///android_asset(有三个 /)。


我会查找list-hack。但是使用new File(file:///android_asset/foo.bar)似乎不起作用。我真的不知道我得到了什么类型的对象,但它对于isDirectory()和(!)isFile()两个测试都失败了。 - nuala
1
我希望我能为这个答案投两票。如果filename是一个文件,String[] s = am.list(filename)将会抛出一个IOException异常。我真的很喜欢这个解决方案,非常感谢! - nuala
然而,list()非常慢(请参见其他答案) - Petrus Repo

4

在我的特定情况下,常规文件的名称类似于filename.ext,而目录只有名称,没有扩展名,并且它们的名称从不包含“.”(点)字符。 因此,可以通过以下方式测试其名称来区分常规文件和目录:

filename.contains(".")

如果您的情况也是这样,同样的解决方案应该适用于您。

1
太棒了!让我的加载时间节省了高达80%。 - Andrei Mărcuţ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接