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

How to fetch all pdf file from all directories in my Android app

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

注意:我正在使用 Android Studio(语言:Java)。

您可以使用 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;
}

我搜索了几乎所有的答案,但它在 Android11 中不起作用。所以我有一个简短的解决方案来获取所有文件,例如图像、视频、pdf、文档、音频等。是最近创建的 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
}

这是@Shay Kin 的即兴回答

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

MediaStore api and Storage Access Framework apis provides access to shared files. This is explained clearly in this video.

得出答案,在 Shay Kin 的回答中,我们可以获取共享文件中的所有 pdf 文件,但忽略 downloads.

需要权限

READ_EXTERNAL_STORAGE

if api is Q plus you also need 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;
}

希望这有效。