如何从我的 Android 应用程序中的所有目录中获取所有 pdf 文件

Posted

技术标签:

【中文标题】如何从我的 Android 应用程序中的所有目录中获取所有 pdf 文件【英文标题】:How to fetch all pdf file from all directories in my Android app 【发布时间】:2021-05-26 22:45:50 【问题描述】:

我想知道如何从内部存储中获取所有 PDF 文件。文件可以位于任何目录中,例如 DCIM 文件夹中的一些文件或 Downloads 文件夹中的文件等等。

注意:我使用的是 android Studio(语言:Java)。

【问题讨论】:

通过new File()获取根目录。 File 类还提供了一个 listFile() 方法。使用它来获取文件夹中的所有文件。享受递归并注意,它可能会导致滞后!!!现在您应该检查每个文件是否都是 .pdf,通过 String#contains() 检查文件名是否包含“.pdf”扩展名。对于您找到的每个 pdf 文件,将其保存在 File 数组中。请记住,由于 linux 内核(基于 Android)的安全性,您可能会遇到一些问题,因此请确保您无法检查某些文件夹... 或者试试Shay Kin 说的。我还没用过 MediaStore @DynoZ 你建议的解决方案won't work on newer Android versions. 【参考方案1】:

您可以使用 MediaStore 获取所有 PDF 文件,这是获取所有 PDF 文件的示例:

   protected ArrayList<String> getPdfList() 
    ArrayList<String> pdfList = new ArrayList<>();
    Uri collection;

    final String[] projection = new String[]
            MediaStore.Files.FileColumns.DISPLAY_NAME,
            MediaStore.Files.FileColumns.DATE_ADDED,
            MediaStore.Files.FileColumns.DATA,
            MediaStore.Files.FileColumns.MIME_TYPE,
    ;

    final String sortOrder = MediaStore.Files.FileColumns.DATE_ADDED + " DESC";

    final String selection = MediaStore.Files.FileColumns.MIME_TYPE + " = ?";

    final String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("pdf");
    final String[] selectionArgs = new String[]mimeType;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) 
        collection = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
    else
        collection = MediaStore.Files.getContentUri("external");
    


    try (Cursor cursor = getContentResolver().query(collection, projection, selection, selectionArgs, sortOrder)) 
        assert cursor != null;

        if (cursor.moveToFirst()) 
            int columnData = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA);
            int columnName = cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME);
            do 
                pdfList.add((cursor.getString(columnData)));
                Log.d(TAG, "getPdf: " + cursor.getString(columnData));
                //you can get your pdf files
             while (cursor.moveToNext());
        
    
    return pdfList;

【讨论】:

这样也可以从 sdcard 访问文件。 非常感谢 Shay kin,但我遇到了一个问题。它显示了所有不在我内部和 sd 存储中的 pdf 文件。我认为这种方法也在获取已删除的 pdf。 对于 sd 卡中的文件我还没有尝试媒体但对于已删除的文件可能是 MediaStore 尚未刷新所以当您访问文件时不要忘记检查是否存在跨度> 我不知道如何使用媒体商店来做到这一点。 这在 Android 11 上不起作用,它不会获取 pdf mimetype 文件【参考方案2】:

我搜索了几乎所有的 ans,但它在 Android 11 中不起作用。所以我有一个简短的解决方案来获取所有文件,例如图像、视频、pdf、doc、音频等。有一个 github 库,它是最近创建的

点击[这里]https://github.com/HBiSoft/PickiT

如果你想在没有依赖的情况下完成这一切

下面的代码

按顺序做
var mimeTypes = arrayOf(
    "application/msword",
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",  // .doc & .docx
    "application/vnd.ms-powerpoint",
    "application/vnd.openxmlformats-officedocument.presentationml.presentation",  // .ppt & .pptx
    "application/vnd.ms-excel",
    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",  // .xls & .xlsx
    "application/pdf"
)

 findViewById<Button>(R.id.btnclick).setOnClickListener 

        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply 
            addCategory(Intent.CATEGORY_OPENABLE)
            type = "*/*"
            putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);

            // mimeTypes = mimeTypes
        

        startActivityForResult(intent, 100)

    

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
    super.onActivityResult(requestCode, resultCode, data)
    Log.e(">>>>>>", "check")

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) 
        getFile(this,intentToDocumentFiles(data)[0])
    


 private fun intentToDocumentFiles(intent: Intent?): List<DocumentFile> 
    val uris = intent?.clipData?.run 
        val list = mutableListOf<Uri>()
        for (i in 0 until itemCount) 
            list.add(getItemAt(i).uri)
        
        list.takeIf  it.isNotEmpty() 
     ?: listOf(intent?.data ?: return emptyList())

    return uris.mapNotNull  uri ->
        if (uri.isDownloadsDocument && Build.VERSION.SDK_INT < 28 && uri.path?.startsWith("/document/raw:") == true) 
            val fullPath = uri.path.orEmpty().substringAfterLast("/document/raw:")
            DocumentFile.fromFile(File(fullPath))
         else 
            fromSingleUri(uri)
        
    .filter  it.isFile 


@RequiresApi(Build.VERSION_CODES.R)
fun getFile(context: Context, document: DocumentFile): File? 
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) 
        return null
    
    try 
        val volumeList: List<StorageVolume> = context
            .getSystemService(StorageManager::class.java)
            .getStorageVolumes()
        if (volumeList == null || volumeList.isEmpty()) 
            return null
        

        // There must be a better way to get the document segment
        val documentId = DocumentsContract.getDocumentId(document.uri)
        val documentSegment = documentId.substring(documentId.lastIndexOf(':') + 1)
        for (volume in volumeList) 
            val volumePath: String
            if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) 
                val class_StorageVolume = Class.forName("android.os.storage.StorageVolume")
                val method_getPath: Method = class_StorageVolume.getDeclaredMethod("getPath")
                volumePath=method_getPath.invoke(volume).toString()
             else 
                // API 30
                volumePath=volume.directory!!.path
            
            val storageFile = File(volumePath + File.separator + documentSegment)

            // Should improve with other checks, because there is the
            // remote possibility that a copy could exist in a different
            // volume (SD-card) under a matching path structure and even
            // same file name, (maybe a user's backup in the SD-card).
            // Checking for the volume Uuid could be an option but
            // as per the documentation the Uuid can be empty.
            val isTarget = (storageFile.exists()
                    && storageFile.lastModified() == document.lastModified()
                    && storageFile.length() == document.length())
            if (isTarget) 
                Log.e(">>>>>>>",storageFile.absolutePath)
                return storageFile
            
        
     catch (e: Exception) 
        e.printStackTrace()
    
    Log.e(">>>>>>>","null")
    return null

【讨论】:

【参考方案3】:

这是@Shay Kin 的即兴回答。

我们知道,在最新的 android 版本中,我们对访问外部存储中的文件有很多限制。

MediaStore api 和 Storage Access Framework api 提供对共享文件的访问。这在this video 中有清楚的解释。

说到答案,在 Shay Kin 的回答中,我们可以获取共享文件中存在但忽略下载的所有 pdf 文件。

需要权限

READ_EXTERNAL_STORAGE

如果api是Q+还需要MANAGE_EXTERNAL_STORAGE

请找到以下代码以获取所有 pdf 文件。

protected List<String> getPdfList() 
    List<String> pdfList = new ArrayList<>();

    final String[] projection = new String[]
            MediaStore.Files.FileColumns.DISPLAY_NAME,
            MediaStore.Files.FileColumns.DATE_ADDED,
            MediaStore.Files.FileColumns.DATA,
            MediaStore.Files.FileColumns.MIME_TYPE,
    ;

    final String sortOrder = MediaStore.Files.FileColumns.DATE_ADDED + " DESC";

    final String selection = MediaStore.Files.FileColumns.MIME_TYPE + " = ?";

    final String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("pdf");
    final String[] selectionArgs = new String[]mimeType;
    
    Uri collection = MediaStore.Files.getContentUri("external");
    pdfList.addAll(getPdfList(collection, projection, selection, selectionArgs, sortOrder));

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) 
        collection = MediaStore.Downloads.getContentUri("external");
        pdfList.addAll(getPdfList(collection,projection, selection, selectionArgs, sortOrder));
    
    
    return pdfList;


private List<String> getPdfList(Uri collection, String[] projection, String selection, String[] selectionArgs, String sortOrder) 
    List<String> pdfList = new ArrayList<>();

    try (Cursor cursor = getContentResolver().query(collection, projection, selection, selectionArgs, sortOrder)) 
        assert cursor != null;

        if (cursor.moveToFirst()) 
            int columnData = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA);
            do 
                pdfList.add((cursor.getString(columnData)));
                Log.d(TAG, "getPdf: " + cursor.getString(columnData));
                //you can get your pdf files
             while (cursor.moveToNext());
        
    
    return pdfList;

希望这行得通。

【讨论】:

以上是关于如何从我的 Android 应用程序中的所有目录中获取所有 pdf 文件的主要内容,如果未能解决你的问题,请参考以下文章

如何从我的 Android 应用程序访问新的 Gmail API?

Android,如何从我的数据库更新列表视图中的选定项目?

如何将文件从我的系统下载文件夹导入到原始目录中

如何将崩溃信息从我的 Android 应用程序发送到我的服务器? [复制]

如何从我的 perl 脚本调用同一目录中的脚本

如何从android中的循环跳转?