如何在ListView中仅显示SD卡/内部存储的Zip文件(不含文件夹)
解决ListView展示所有Zip文件(仅文件,不显示文件夹)的问题
嘿,我看了你的代码,问题出在你的ZipFilter逻辑上——它现在的作用是判断某个文件夹里是否包含Zip文件,如果包含就把这个文件夹显示出来,而不是直接筛选出Zip文件本身。咱们来一步步修正它,实现你要的效果:
第一步:修改ZipFilter,只识别Zip文件,拒绝所有文件夹
首先把原来的Filter改成只接受Zip格式的文件,完全不通过任何文件夹:
class ZipFilter implements FileFilter { protected static final String TAG = "ZipFileFilter"; @Override public boolean accept(File f) { // 拒绝隐藏文件、不可读文件,以及所有文件夹 if (f.isHidden() || !f.canRead() || f.isDirectory()) { return false; } // 检查文件扩展名是否为Zip String ext = getFileExtension(f); if (ext == null) return false; try { return SupportedFileFormat.valueOf(ext.toUpperCase()) != null; } catch(IllegalArgumentException e) { // 扩展名不在支持列表里,返回false return false; } } // 提取文件扩展名的工具方法 private String getFileExtension(File f) { String fileName = f.getName(); int dotPosition = fileName.lastIndexOf('.'); return (dotPosition == -1) ? null : fileName.substring(dotPosition + 1); } }
第二步:递归遍历所有目录,收集所有Zip文件
现在需要一个方法,递归遍历内部存储/SD卡的所有子目录,把所有符合条件的Zip文件收集起来——因为listFiles()只会遍历当前目录,不会深入子文件夹:
private ArrayList<File> collectAllZipFiles(File rootDirectory) { ArrayList<File> zipFileList = new ArrayList<>(); // 如果传入的不是有效目录,直接返回空列表 if (!rootDirectory.exists() || !rootDirectory.isDirectory()) { return zipFileList; } // 先收集当前目录下的所有Zip文件 File[] currentDirZips = rootDirectory.listFiles(new ZipFilter()); if (currentDirZips != null) { Collections.addAll(zipFileList, currentDirZips); } // 递归遍历所有子目录,收集里面的Zip文件 File[] subDirectories = rootDirectory.listFiles(new FileFilter() { @Override public boolean accept(File f) { // 只遍历可读取、非隐藏的文件夹 return f.isDirectory() && !f.isHidden() && f.canRead(); } }); if (subDirectories != null) { for (File subDir : subDirectories) { zipFileList.addAll(collectAllZipFiles(subDir)); } } return zipFileList; }
第三步:把收集到的文件绑定到ListView
在你的Activity/Fragment里调用上面的方法,获取所有Zip文件,然后给ListView设置适配器:
// 获取内部存储根目录(Android 10及以下可用,需要READ_EXTERNAL_STORAGE权限) File internalStorageRoot = Environment.getExternalStorageDirectory(); // 收集所有Zip文件 ArrayList<File> allZipFiles = collectAllZipFiles(internalStorageRoot); // 用ArrayAdapter绑定数据到ListView(你也可以自定义Adapter显示更多文件信息) ArrayAdapter<File> zipAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, allZipFiles); yourListView.setAdapter(zipAdapter);
针对Android 10+的注意事项
从Android 10(API 29)开始,Scoped Storage限制了直接访问文件系统,上面的方法可能无法正常工作。推荐用MediaStore来查询所有Zip文件,更符合系统权限要求:
private ArrayList<String> getZipFilesViaMediaStore(Context context) { ArrayList<String> zipFilePaths = new ArrayList<>(); // 查询Zip文件的MIME类型 String[] projection = {MediaStore.Files.FileColumns.DATA}; String selection = MediaStore.Files.FileColumns.MIME_TYPE + " = ? OR " + MediaStore.Files.FileColumns.MIME_TYPE + " = ?"; String[] selectionArgs = {"application/zip", "application/x-zip-compressed"}; Cursor cursor = context.getContentResolver().query( MediaStore.Files.getContentUri("external"), projection, selection, selectionArgs, null ); if (cursor != null) { while (cursor.moveToNext()) { String filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA)); zipFilePaths.add(filePath); } cursor.close(); } return zipFilePaths; }
调用这个方法后,你可以把文件路径列表转换成File对象,或者直接显示路径到ListView里。
为什么原来的代码不行?
原来的checkDirectory方法会判断“当前文件夹里是否有Zip文件”,如果有的话就返回true,所以listFiles()会把这个文件夹返回给你,导致ListView显示的是包含Zip的文件夹,而不是Zip文件本身。咱们现在的逻辑是直接筛选出所有Zip文件,再把它们收集起来展示,就解决了这个问题。
内容的提问来源于stack exchange,提问作者red viper
相关产品推荐
相关产品推荐

