判断android资产入口是文件还是目录

Posted

技术标签:

【中文标题】判断android资产入口是文件还是目录【英文标题】:determine whether android asset entry is a file or directory 【发布时间】:2011-12-06 12:30:30 【问题描述】:

嘿嘿,

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

我很难为/assets 中的任何资源获取文件对象。但我认为我依赖于此,因为我需要 File.isDirectory() 之类的东西来确定我是否必须开始复制或深入研究系统。

我的第一种方法是使用Assets Manager,但该课程似乎没有提供我需要的信息。最有希望的原因是获得AssetFileDescriptor 并转到[FileDescriptor][2]。但是他们似乎都没有isDirectory-方法。

所以我的另一种方法是直截了当的:创建一个文件对象并快乐。但是,我似乎遇到了缺少正确路径来实例化文件对象的问题。我知道file://android_asset,但它似乎不适用于fileconstructor。

我的最后一个想法是利用 InputStream(无论如何我都需要它来复制)并以某种方式过滤字节以获得表明该资源是目录的重要位。这是一个非常老套的解决方案,可能正处于无效的地狱中,但我看不出有其他方法可以解决这个问题。

【问题讨论】:

您还可以查看***.com/a/46827944/2179872,它结合了 AssetManager.list()AssetManager.open () 方法 【参考方案1】:

我遇到了同样的问题。在某些时候我意识到list() 真的很慢(每次调用 50 毫秒),所以我现在使用不同的方法:

我有一个(eclipse)ant-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;
    

【讨论】:

这很好用,但我需要在 pathconvert 中添加 'dirsep="/"'。否则在 Windoze Java 上说路径分隔符是 '\',这在 Android 资产管理器中不起作用 对于那些为此苦苦挣扎并使用 Gradle 的人,请参阅***.com/questions/18569983/… 我正在使用gradle,有没有使用gradle的解决方案?【参考方案2】:

list() list() list() 如果您尝试获取文件列表,但在目录中获取有效响应,AssetManager 可能会给出空/零长度数组/IOException。

但否则应该是 file:///android_asset (with 3 /)

【讨论】:

我会看看列表黑客。是的,但使用 new File(file:///android_asset/foo.bar) 似乎不起作用。我真的不知道我会返回什么类型的对象,但它对于两个测试都失败了:isDirectory() AND (!) isFile()。 我希望我能对这个答案进行双重投票。 String[] s = am.list(filename) 将抛出 IOException 以防文件名是文件。我真的很喜欢这个解决方案,非常感谢! 但是,list() 真的很慢(见其他答案)【参考方案3】:

在我的具体情况下,常规文件的名称类似于 filename.ext,而目录只有名称,没有扩展名,并且它们的名称从不包含“。” (点)字符。 所以一个普通的文件可以通过如下测试它的名字来与一个目录区分开来:

filename.contains(".")

如果您也是这种情况,那么同样的解决方案应该也适合您。

【讨论】:

太棒了!为我节省了高达 80% 的正常加载时间。

以上是关于判断android资产入口是文件还是目录的主要内容,如果未能解决你的问题,请参考以下文章

js判断手机端(Android手机还是iPhone手机)

APK 大小比预期的要大 - android studio

用于 Android 库 (aar) 的 assets/ 目录中的资产

在 Android Studio 中添加资产文件夹

Android是如何使用AndroidManifest.xml的?

获取资产文件夹的完整路径