【问题标题】:Android _data' does not exist on getContentResolvergetContentResolver 上不存在 Android _data'
【发布时间】:2020-08-31 17:14:01
【问题描述】:

getColumnIndexOrThrow 抛出异常的原因可能是什么

java.lang.IllegalArgumentException:列“_data”不存在。可用列:[]

但是,如果您重命名文件并重试,它会起作用吗?

private static String getDataColumn(Context context, Uri uri, String selection,
                                       String[] selectionArgs) {
        Cursor cursor = null;
        final String[] projection = {
                MediaStore.Files.FileColumns.DATA
        };
        try {
            cursor = context.getContentResolver().query(
                    uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int cindex = cursor.getColumnIndexOrThrow(projection[0]);
                return cursor.getString(cindex);
            }
        }
             catch (Exception e) {
                e.printStackTrace();
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }

原始文件的意图是

content://com.sec.android.app.myfiles.FileProvider/device_storage/Download/myfile.pdf

但重命名的文件是

content://0@media/external/file/588

【问题讨论】:

  • 因此,如果我只是在原始文件上使用 uri.getPath() 路径返回(无效)为/device_storage/Download/myFile.pdf 这是我的文件打开例程的无效路径,但如果我重命名它然后再试一次它回来了:/storage/emulated/0/Download/myFile.pdf 哪个打开文件就好了?想法?
  • 任何人都知道为什么 MyFiles 应用程序会出现此问题,而其他资源管理器应用程序会发送正确的 getData()?
  • 请解释一下您实际上想要做什么?您之前所做的和之后的预期。以及何时抛出此异常。
  • 我有一个活动来处理文件的打开并在清单中注册类型,以便我可以用来打开该类型的文件。在一种情况下,getData() 返回如上所示的一个字符串,该字符串不会解析为有效的文件路径。但是,如果我在外部文件导出器中重命名文件并重试,返回的 getData 字符串是有效的。
  • 我已经为答案添加了额外的材料。

标签: android android-contentresolver


【解决方案1】:

MediaStore.Files.FileColumns.DATA 已弃用,column '_data' 不再存在。

正如Android Developer所说的

此常量在 API 级别 29 中已弃用。

应用程序可能没有直接访问此路径的文件系统权限。 而不是尝试 要直接打开此路径,应用程序应使用 ContentResolver#openFileDescriptor(Uri, String) 获取访问权限。

如何使用openFileDescriptor

我尝试在跨应用程序中引入 2 个不同的广泛使用文件的示例

图像文件

if(uri==null)return;
ContentResolver contentResolver = getActivity().getContentResolver();
if(contentResolver==null)return;
ParcelFileDescriptor parcelFileDescriptor = contentResolver.openFileDescriptor(uri,"rw");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
if(fileDescriptor==null)return;
Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();

如何处理bitmap的例子很多

非图像文件

if(uri==null)return;
ContentResolver contentResolver = getActivity().getContentResolver();
if(contentResolver==null)return;
ParcelFileDescriptor parcelFileDescriptor = contentResolver.openFileDescriptor(uri,"rw");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
if(fileDescriptor==null)return;
FileInputStream fileInputStream = new FileInputStream(fileDescriptor);
FileOutputStream fileOutputStream = new FileOutputStream(fileDescriptor);
parcelFileDescriptor.close();

如何处理FileInputStreamFileOutputStream的例子很多

结论

尝试获取absolute Path 是没有意义的,尽管除非引发安全和隐私问题,否则没有必要。事实上,Relative path 足以处理文件,kernel Mode 和@987654333 之间有Abstract Representation implementations @ 可以将Relative Path 映射到Absolute Path 并且用户不需要知道。

openFileDescriptor 速度非常快,兼容所有安卓版本

【讨论】:

  • 是使用 intent.getData().getPath 执行此操作的正确方法吗?如果是这样,MyFiles 发送的数据仍然中断,但是其他文件浏览器应用程序发送了正确的信息?这是在运行 Android 10 的 Note10 Plus 上
  • 感谢您的解释。我的问题是,我必须将绝对路径字符串传递给我正在调用的库,而不是描述符或流。
猜你喜欢
  • 2013-09-22
  • 2017-07-19
  • 1970-01-01
  • 1970-01-01
  • 2011-04-14
  • 1970-01-01
  • 1970-01-01
  • 2021-11-14
  • 1970-01-01
相关资源
最近更新 更多