文件浏览的常用实现文件浏览的功能,实现方式有好几种,这里介绍几种常用的方式:
现在来分析分析三种有什么优缺点: MediaStore
MediaStore会在系统内部维护一张SQLite表,然后通过ContentResolver的方式就可以获取到SQLite表中记录的文件。通过MediaStore可以很方便的写类似SQL语句来进行查询,并且文件的格式、名称、尺寸等,都有特定的字段去标识。
external.png
从图中可以看到,external.db中包含了一个“files”的Table,内部维护了外部存储器里所有需要被维护的文件。而它还有对特定类型的文件类型进行了视图显示,例如:Images、video。
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类里的相关方法:
上面介绍的方法里,大部分看描述就可以知道用途了,但是用来做文件管理器,主要的一个方法就是listFiles(),它是可以得到查询的目录的内的文件和目录的。并且提供一个FileFilter的类去用来过滤需要的文件,这个FileFilter处理的是一个File对象,如果仅对文件名有过滤要求,可以使用FIlenameFilter来过滤,但是FileFilter使用起来会更灵活一些。 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,这种方式完全是满足需求的 (责任编辑:最模板) |