【问题标题】:How to fetch all pdf file from all directories in my Android app如何从我的 Android 应用程序中的所有目录中获取所有 pdf 文件
【发布时间】: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.

标签: java android android-internal-storage


【解决方案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 apiStorage 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;
    }
    

    希望这行得通。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-19
      • 1970-01-01
      • 2010-11-28
      • 2021-09-20
      • 1970-01-01
      • 2016-03-07
      相关资源
      最近更新 更多