如何从我的 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?