Android应用中遍历Assets的结果

本文探讨了在Android应用中遍历Assets时遇到的意外文件现象,通过分析AssetManager的源码,揭示了系统Assets的存在,并介绍了如何通过反射访问。同时,指出当apk与系统文件路径相同,apk文件会覆盖系统文件,最后提到了访问apk压缩文件根目录的限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在研究如何遍历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.txt
MyFile2.txt
MyFolder1
	MyFile1.txt
	MySubFolder1
		MyFile1-1.txt
MyFolder3
	MyFile2.txt
MyFolder4
	MySubFolder4
		MyFile1.txt
device_features
	H2X_I18N.xml
	HM2013022.xml
	HM2013023.xml
	HM2014011.xml
	HM2014112.xml
	HM2014501.xml
	HM2014811.xml
	HM2014812.xml
	HM2014813.xml
	HM2014817.xml
	HM2014818.xml
	HM2014819.xml
	HM2014821.xml
	aries.xml
	armani.xml
	cancro_MI3.xml
	cancro_MI4.xml
	dior.xml
	ferrari.xml
	gucci.xml
	hammerhead.xml
	lcsh92_wet_jb9.xml
	lcsh92_wet_tdd.xml
	leo.xml
	lte26007.xml
	mocha.xml
	pisces.xml
	taurus.xml
	virgo.xml
huangli.idf
images
	android-logo-mask.png
	android-logo-shine.png
license
	br
		pt_BR
			eula.html
			privacy.html
	default
		en_US
			copyright.html
			eula.html
			mibilicense.html
			miclouduseragreement.htm
			privacy.html
		zh_CN
			copyright.html
			eula.html
			mibilicense.html
			miclouduseragreement.htm
			privacy.html
		zh_TW
			copyright.html
			eula.html
			miclouduseragreement.htm
			privacy.html
	sg
		en_US
			privacy.html
pinyinindex.idf
sounds
	bootanim0.raw
	bootanim1.raw
telocation.idf
webkit
	android-weberror.png
	hyph_en_US.dic
	incognito_mode_start_page.html
	missingImage.png
	nullPlugin.png
	play.png
	textAreaResizeCorner.png
	togglePlugin.png
	youtube.html
	youtube.png
东西很多,但是在我应用的Assets下的文件夹结构是这样的:

MyFile1.txt
MyFile2.txt
MyFolder1
	MyFile1.txt
	MySubFolder1
		MyFile1-1.txt
MyFolder3
	MyFile2.txt
MyFolder4
	MySubFolder4
		MyFile1.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.xml
META-INF
assets
classes.dex
lib
res
resources.arsc

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




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

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值