Android应用中遍历Assets的结果

来源:互联网 发布:mysql免费 编辑:程序博客网 时间:2024/04/29 19:47

在研究如何遍历Assets下的文件时,我得到了一点奇怪的结果 - 看到了一些本不属于当前应用的文件结构。


首先贴一下遍历代码

public static void printAssets(Context c) {AssetManager am = c.getAssets();printAssetsFiles(am, "", "");}public static void printAssetsFiles(AssetManager am, String parent, String current, String indent) {    if (!TextUtils.isEmpty(current)) {        System.out.println(indent + current);        indent += "\t";    }    // 列出子文件    String[] files;    String currentParent;    try {        if (TextUtils.isEmpty(parent)) {            currentParent = current;        } else {            currentParent = parent + "/" + current;        }        files = am.list(currentParent);    } catch (IOException e1) {        return;    }    if (files != null && files.length > 0) {        for (String f : files) {            printAssetsFiles(am, currentParent, f, indent);        }    }}

下面是在我手机上跑出来的结果,运行环境是小米4,Android4.4.4

MyFile1.txtMyFile2.txtMyFolder1MyFile1.txtMySubFolder1MyFile1-1.txtMyFolder3MyFile2.txtMyFolder4MySubFolder4MyFile1.txtdevice_featuresH2X_I18N.xmlHM2013022.xmlHM2013023.xmlHM2014011.xmlHM2014112.xmlHM2014501.xmlHM2014811.xmlHM2014812.xmlHM2014813.xmlHM2014817.xmlHM2014818.xmlHM2014819.xmlHM2014821.xmlaries.xmlarmani.xmlcancro_MI3.xmlcancro_MI4.xmldior.xmlferrari.xmlgucci.xmlhammerhead.xmllcsh92_wet_jb9.xmllcsh92_wet_tdd.xmlleo.xmllte26007.xmlmocha.xmlpisces.xmltaurus.xmlvirgo.xmlhuangli.idfimagesandroid-logo-mask.pngandroid-logo-shine.pnglicensebrpt_BReula.htmlprivacy.htmldefaulten_UScopyright.htmleula.htmlmibilicense.htmlmiclouduseragreement.htmprivacy.htmlzh_CNcopyright.htmleula.htmlmibilicense.htmlmiclouduseragreement.htmprivacy.htmlzh_TWcopyright.htmleula.htmlmiclouduseragreement.htmprivacy.htmlsgen_USprivacy.htmlpinyinindex.idfsoundsbootanim0.rawbootanim1.rawtelocation.idfwebkitandroid-weberror.pnghyph_en_US.dicincognito_mode_start_page.htmlmissingImage.pngnullPlugin.pngplay.pngtextAreaResizeCorner.pngtogglePlugin.pngyoutube.htmlyoutube.png
东西很多,但是在我应用的Assets下的文件夹结构是这样的:

MyFile1.txtMyFile2.txtMyFolder1MyFile1.txtMySubFolder1MyFile1-1.txtMyFolder3MyFile2.txtMyFolder4MySubFolder4MyFile1.txt


在这里我们会发现,输出列表中包含大量的文件,这些文件都不是我们应用中的。

(在这里说两句题外话,输出列表中是没有空目录的,是因为apk在打包的时候把空目录过滤了,大家可以用压缩软件打开看看)


那么多出来的文件都是从哪里来的呢?我们去扒一扒AssetManager的源码,先从list方法开始:

/**     * Return a String array of all the assets at the given path.     *      * @param path A relative path within the assets, i.e., "docs/home.html".     *      * @return String[] Array of strings, one for each asset.  These file     *         names are relative to 'path'.  You can open the file by     *         concatenating 'path' and a name in the returned string (via     *         File) and passing that to open().     *      * @see #open     */    public native final String[] list(String path)        throws IOException;
这是个本地的方法,虽然没有源码,但是从注释中也能看出来,“all the assets”说明这里不是只有一个Assets目录的,那么除了我们自己的apk,肯定不能是其他人的apk啊,那就只能是系统的Assets了。

再翻代码,发现AssetManager中有个静态的实例sSystem,看起来这就是系统的Assets了。这个类中有一个getSystem方法,是获取该实例的。这是个隐藏方法,我们可以用反射获取:

Method getSystem = AssetManager.class.getDeclaredMethod("getSystem");AssetManager am = (AssetManager) getSystem.invoke(null);

遍历这个AssetManager的目录,可以得到上面多出来的文件列表。至于这个Assets文件的位置在哪里,我没有找到,有兴趣的读者可以找找。


另外,如果apk Assets下的文件路径和系统中的文件路径相同,那么在读取的时候,apk自己的文件会覆盖系统文件,所以不需要担心此问题。



最后,值得一提的是,如果我么使用如下参数调用上面的方法:

printAssetsFiles(am, "/", "");

得到的将是apk压缩文件的根目录结构如下:

AndroidManifest.xmlMETA-INFassetsclasses.dexlibresresources.arsc

此时使用am.open打开文件,只能得到异常。不过对于文件,比如AndroidManifest.xml,可以使用AssetManager的隐藏api方法openNonAsset打开,但是对于目录就无能为力了,当然,API是不建议用户用AssetManager打开这个文件的(所以文档中称呼这些文件为NonAsset文件)




CyanFlxy原创,转载请注明出处。

1 0
原创粉丝点击