服务报价 | 域名主机 | 网络营销 | 软件工具| [加入收藏]
 热线电话: #

Android实现一个简单的文件浏览器

时间:2017-01-12 23:49来源:未知 作者:最模板 点击:
有时候会碰到一些文件浏览的需求,但是App本身又并非一个文件管理相关的App,可能只是某个功能,需要让用户来选择文件进行后续操作。所以这里只是为了实现一个简单的文件浏览的

有时候会碰到一些文件浏览的需求,但是App本身又并非一个文件管理相关的App,可能只是某个功能,需要让用户来选择文件进行后续操作。所以这里只是为了实现一个简单的文件浏览的功能,如果需要实现一整套文件管理的功能,请换方案或者自行添加功能。

文件浏览的常用实现

文件浏览的功能,实现方式有好几种,这里介绍几种常用的方式:

  • 使用MediaStore方式,直接获取到所有的有效文件,再进行文件夹组合。
  • 使用Runtime.getRuntion().exec("cmdline")直接执行命令行命令,然后解析返回结果。
  • 使用File类的方式来访问目录之下所有的文件。

现在来分析分析三种有什么优缺点:

MediaStore

MediaStore会在系统内部维护一张SQLite表,然后通过ContentResolver的方式就可以获取到SQLite表中记录的文件。通过MediaStore可以很方便的写类似SQL语句来进行查询,并且文件的格式、名称、尺寸等,都有特定的字段去标识。
下面给出一个external.db的SQLite表结构:


external.png

从图中可以看到,external.db中包含了一个“files”的Table,内部维护了外部存储器里所有需要被维护的文件。而它还有对特定类型的文件类型进行了视图显示,例如:Images、video。
如果仅仅是需要做到文件浏览,可以直接通过MediaStore分别查询内部存储器和外部存储器的files表即可。
file表的结构如下图:


table_files.png

使用MediaStore使用起来非常的方便,详细的使用方式这里就不介绍了。但是使用MediaStore还是有一些问题的,例如第三方App保存的文件,如果第三方App没有处理的话,可能你需要等到下次重启之后,才能通过MediaStore扫描到,它会在重启、Sdcard装载等时机,重新扫描刷新。当然也有办法自动去刷新,只需要发送一个对应的Broadcast即可,但是也是有坑的,大概是在Android 4.0+之后,只能指定目录进行刷新,所以需要维护大量的目录来做。这里就不展开讨论了,具体的可以自行百度。

CmdLine

使用Runtion.getRuntion.exec()的方式直接执行例如:cd、ls等命令行命令,然后读取输出结果进行解析,就可以拿到对应目录下的文件信息。这种方式使用起来其实也非常的方便,而且效率也是有保障的,但是解析数据上,操作的数据是大量的String,可能在开发的时候,不够直观需要处理各种占位、符换行符等问题上耗时。

至于如何使用Runtime,同样不展开讨论了。


Paste_Image.png

File类

对的,上面两个不展开讨论的方案,都不是本片的主题,下面就要进入主题了。本片主要就是用一个File类来实现文件浏览的功能。

仔细阅读File类的源码,可以发现,它核心的方法全是native,在Android源码中,使用到native的方法,在效率上都不会太差。而File类同样也提供了一些文件浏览相关的方法,当然最终还是调用到native里了。使用File自己提供的一些方法,完全可以实现一个对简单的文件浏览器的

使用File实现文件浏览器

既然要用带File类,这里介绍先几个File类里的相关方法:

  • String getName() :得到当前文件名
  • String getParent():得到当前文件上一级目录的文件名
  • File getParentFile():得到当前文件上一级的文件File对象
  • String getAbsolutePath():得到当前文件的绝对路径
  • boolean isDirectory() : 判断当前文件是否是一个目录
  • boolean isFile(): 判断当前文件是否是一个文件
  • long lastModified():得到文件最后修改时间
  • long length():得到文件的长度。
  • File[] listFiles(FileFilter fileter):查询此文件夹内的文件和目录

上面介绍的方法里,大部分看描述就可以知道用途了,但是用来做文件管理器,主要的一个方法就是listFiles(),它是可以得到查询的目录的内的文件和目录的。并且提供一个FileFilter的类去用来过滤需要的文件,这个FileFilter处理的是一个File对象,如果仅对文件名有过滤要求,可以使用FIlenameFilter来过滤,但是FileFilter使用起来会更灵活一些。
从源码里可以看到,FileFilter是一个接口类,它内部只需要实现accept()方法,这个方法会在得到子目录的列表的时候,遍历列表去过滤掉不符合条件File对象。

package java.io;

/**
 * An interface for filtering {@link File} objects based on their names
 * or other information.
 *
 * @see File#listFiles(FileFilter)
 */
public interface FileFilter {

    /**
     * Indicating whether a specific file should be included in a pathname list.
     *
     * @param pathname
     *            the abstract file to check.
     * @return {@code true} if the file should be included, {@code false}
     *         otherwise.
     */
    public abstract boolean accept(File pathname);
}

既然基于File的文件浏览的主要是需要实现FileFilter这个接口,那么这里给出一个简单的实现示例,只是用来扫描目录下所有的APK文件。

public class PFileFilter implements FileFilter {
    @Override
    public boolean accept(File pathname) {
        if (pathname.exists()) {

            if (pathname.isDirectory() && pathname.canRead() && pathname.canWrite()) {
                // 文件夹只要可读可写 就返回
                return pathname.listFiles().length > 0;
            }

            if (pathname.isFile() && pathname.canRead() && pathname.canWrite()) {
                // 文件还需要满足固定后缀
                if (pathname.getName().toLowerCase().endsWith(".apk")) {
                    return true;
                }
            }
        }
        return false;
    }
}

按业务需求实现了FileFilter,接下来只需要调用调用File.listFiles(),就可以拿到符合需求的File[]了。

完整的帮助类

虽然使用File.listFiles()配合FileFilter方法就可以实现文件的简单浏览。但是可能还需要一些简单的帮助类,例如拿到文件最后修改时间、得到文件的MimeType、得到文件的后缀等等需求。这里简单的对File进行了一个封装类,就不一一介绍了,直接上代码了,有需要可以直接拿来用。

/**
 * Created by 承香墨影 on 2016/5/5.
 */
public class FileMamagerHelper {

    /**
     * 得到特定路径下有效文件
     */
    public static List<File> getFilesByFile(File file) {

        if (file != null && file.exists()) {
            File[] files = file.listFiles(new PFileFilter());
            List<File> filterFile = new ArrayList<>();
            if (Collections.addAll(filterFile, files)) {
                return filterFile;
            }
        }
        return null;
    }

    /**
     * 得到特定路径下有效文件
     */
    public static List<File> getFilesByPath(String path) {
        if (TextUtils.isEmpty(path)) {
            return null;
        }
        File file = new File(path);
        return getFilesByFile(file);
    }

    /**
     * 检查是否存在上一级目录
     *
     * @return
     */
    public static boolean hasParent(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return false;
        }

        File file = new File(filePath);
        return hasParent(file);
    }

    /**
     * 得到上一级目录
     * @param filePath
     * @return
     */
    public static String getParent(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return "";
        }

        File file = new File(filePath);
        return file.getParent();
    }

    /**
     * 检查是否存在上一级目录
     *
     * @return
     */
    public static boolean hasParent(File file) {
        if (file != null && file.exists()) {
            return file.getParentFile() != null;
        }

        return false;
    }

    /**
     * 得到文件名
     */
    public static String getFileName(File file) {
        if (file != null) {
            return file.getName();
        }
        return "";
    }

    /**
     * 返回文件最后修改日期
     */
    public static String getFileLastDate(File file) {
        if (file == null) {
            return "";
        }
        long date = file.lastModified();
        if (date == 0) {
            return "";
        }
        @SuppressLint("SimpleDateFormat")
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
        return simpleDateFormat.format(new Date(date));
    }

    public static String getFileSize(File file) {
        if (file.isFile()) {
            float size = file.length() / 1024f;
            if (size < 1024) {
                if (size < 0.01) {
                    size = 0.01f;
                }
                return String.format("%.2fKB", size);
            }
            size = size / 1024f;
            return String.format("%.2fMB", size);
        }
        return "";
    }

    /**
     * 获得文件的mimeType
     *
     * @param file
     * @return
     */
    public static String getMimeType(File file) {
        String suffix = getSuffix(file);
        if (suffix == null) {
            return "file/*";
        }
        String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(suffix);
        if (type != null || !type.isEmpty()) {
            return type;
        }
        return "file/*";
    }

    /**
     * 获得文件的后缀
     * @param file
     * @return
     */
    private static String getSuffix(File file) {
        if (file == null || !file.exists() || file.isDirectory()) {
            return null;
        }
        String fileName = file.getName();
        if (fileName.equals("") || fileName.endsWith(".")) {
            return null;
        }
        int index = fileName.lastIndexOf(".");
        if (index != -1) {
            return fileName.substring(index + 1).toLowerCase(Locale.US);
        } else {
            return null;
        }
    }
}

有这个工具类,完全可以使用ListView加Adapter的方式,实现一个简单的文件浏览器,就不再提供单独的示例了。

结尾

虽然用File类可以完全可以实现文件浏览器的功能,当然这个并不是最优的解决方案,但是只要不是专业的文件管理器App,这种方式完全是满足需求的

(责任编辑:最模板)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
热点内容