网络上看到过很多种Uri转路径的方法,可基本上都只适用于很少的Uri值,可能没有结果(例如,对于由MediaStore索引的非本地文件),也可能没有可用的结果(例如,对于可移动存储上的文件)。
解决方法
使用ContentResolver和openInputStream()在Uri标识的内容上获取InputStream。在控制的文件上使用InputStream和FileOutputStream复制内容,然后使用该文件。
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26private static String getFilePathForN(Context context, Uri uri) { try { Cursor returnCursor = context.getContentResolver().query(uri, null, null, null, null); int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); returnCursor.moveToFirst(); String name = (returnCursor.getString(nameIndex)); File file = new File(context.getFilesDir(), name); InputStream inputStream = context.getContentResolver().openInputStream(uri); FileOutputStream outputStream = new FileOutputStream(file); int read = 0; int maxBufferSize = 1 * 1024 * 1024; int bytesAvailable = inputStream.available(); int bufferSize = Math.min(bytesAvailable, maxBufferSize); final byte[] buffers = new byte[bufferSize]; while ((read = inputStream.read(buffers)) != -1) { outputStream.write(buffers, 0, read); } returnCursor.close(); inputStream.close(); outputStream.close(); return file.getPath(); } catch (Exception e) { e.printStackTrace(); } return null; }
附上全系统的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145/** * 文件Uri转路径(兼容各品牌手机) */ public class PathUtils { /** * android7.0以上处理方法 */ private static String getFilePathForN(Context context, Uri uri) { try { Cursor returnCursor = context.getContentResolver().query(uri, null, null, null, null); int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); returnCursor.moveToFirst(); String name = (returnCursor.getString(nameIndex)); File file = new File(context.getFilesDir(), name); InputStream inputStream = context.getContentResolver().openInputStream(uri); FileOutputStream outputStream = new FileOutputStream(file); int read = 0; int maxBufferSize = 1 * 1024 * 1024; int bytesAvailable = inputStream.available(); int bufferSize = Math.min(bytesAvailable, maxBufferSize); final byte[] buffers = new byte[bufferSize]; while ((read = inputStream.read(buffers)) != -1) { outputStream.write(buffers, 0, read); } returnCursor.close(); inputStream.close(); outputStream.close(); return file.getPath(); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 全平台处理方法 */ public static String getPath(final Context context, final Uri uri) throws Exception { final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; final boolean isN = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; if (isN) { return getFilePathForN(context, uri); } // DocumentProvider if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { // ExternalStorageProvider if (isExternalStorageDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; if ("primary".equalsIgnoreCase(type)) { return Environment.getExternalStorageDirectory() + "/" + split[1]; } } // DownloadsProvider else if (isDownloadsDocument(uri)) { final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), StringUtils.toLong(id)); return getDataColumn(context, contentUri, null, null); } // MediaProvider else if (isMediaDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; Uri contentUri = null; if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } final String selection = "_id=?"; final String[] selectionArgs = new String[] { split[1] }; return getDataColumn(context, contentUri, selection, selectionArgs); } } // MediaStore (and general) else if ("content".equalsIgnoreCase(uri.getScheme())) { return getDataColumn(context, uri, null, null); } // File else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } /** * 获取此Uri的数据列的值。这对于MediaStore uri和其他基于文件的内容提供程序非常有用。 */ public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { Cursor cursor = null; final String column = "_data"; final String[] projection = { column }; try { cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst()) { final int column_index = cursor.getColumnIndexOrThrow(column); return cursor.getString(column_index); } } catch (IllegalArgumentException e){ //do nothing } finally { if (cursor != null) cursor.close(); } return null; } public static boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri.getAuthority()); } public static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri.getAuthority()); } public static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri.getAuthority()); } }
参考资料:https://stackoverflow.com/questions/42508383/illegalargumentexception-column-data-does-not-exist
另发现一篇,亲测,Android 4.4到Android 10可用,测试的系统有VIVO、OPPO、MIUI、EMUI...
解决的国内产商问题:华为的黄色图标管理器,他返回了4.4的标准的Uri了,不是4.4以上的标准的Uri,导致解析的时候,判断到版本 > 4.4,然后用了4.4以上的标准的解析,然后失败了,并非不回调。
直接可用的代码片段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209public class FileUtils { private Context context; public FileUtils(Context context) { this.context = context; } public String getFilePathByUri(Uri uri) { // 以 file:// 开头的 if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) { return uri.getPath(); } // 以/storage开头的也直接返回 if (isOtherDocument(uri)) { return uri.getPath(); } // 版本兼容的获取! String path = getFilePathByUri_BELOWAPI11(uri); if (path != null) { LogUtils.d("getFilePathByUri_BELOWAPI11获取到的路径为:" + path); return path; } path = getFilePathByUri_API11to18(uri); if (path != null) { LogUtils.d("getFilePathByUri_API11to18获取到的路径为:" + path); return path; } path = getFilePathByUri_API19(uri); LogUtils.d("getFilePathByUri_API19获取到的路径为:" + path); return path; } private String getFilePathByUri_BELOWAPI11(Uri uri) { // 以 content:// 开头的,比如 content://media/extenral/images/media/17766 if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { String path = null; String[] projection = new String[]{MediaStore.Images.Media.DATA}; Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null); if (cursor != null) { if (cursor.moveToFirst()) { int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); if (columnIndex > -1) { path = cursor.getString(columnIndex); } } cursor.close(); } return path; } return null; } private String getFilePathByUri_API11to18(Uri contentUri) { String[] projection = {MediaStore.Images.Media.DATA}; String result = null; CursorLoader cursorLoader = new CursorLoader(context, contentUri, projection, null, null, null); Cursor cursor = cursorLoader.loadInBackground(); if (cursor != null) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); result = cursor.getString(column_index); cursor.close(); } return result; } private String getFilePathByUri_API19(Uri uri) { // 4.4及之后的 是以 content:// 开头的,比如 content://com.android.providers.media.documents/document/image%3A235700 if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (DocumentsContract.isDocumentUri(context, uri)) { if (isExternalStorageDocument(uri)) { // ExternalStorageProvider String docId = DocumentsContract.getDocumentId(uri); String[] split = docId.split(":"); String type = split[0]; if ("primary".equalsIgnoreCase(type)) { if (split.length > 1) { return Environment.getExternalStorageDirectory() + "/" + split[1]; } else { return Environment.getExternalStorageDirectory() + "/"; } // This is for checking SD Card } } else if (isDownloadsDocument(uri)) { //下载内容提供者时应当判断下载管理器是否被禁用 int stateCode = context.getPackageManager().getApplicationEnabledSetting("com.android.providers.downloads"); if (stateCode != 0 && stateCode != 1) { return null; } String id = DocumentsContract.getDocumentId(uri); // 如果出现这个RAW地址,我们则可以直接返回! if (id.startsWith("raw:")) { return id.replaceFirst("raw:", ""); } if (id.contains(":")) { String[] tmp = id.split(":"); if (tmp.length > 1) { id = tmp[1]; } } Uri contentUri = Uri.parse("content://downloads/public_downloads"); LogUtils.d("测试打印Uri: " + uri); try { contentUri = ContentUris.withAppendedId(contentUri, Long.parseLong(id)); } catch (Exception e) { e.printStackTrace(); } String path = getDataColumn(contentUri, null, null); if (path != null) return path; // 兼容某些特殊情况下的文件管理器! String fileName = getFileNameByUri(uri); if (fileName != null) { path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName; return path; } } else if (isMediaDocument(uri)) { // MediaProvider String docId = DocumentsContract.getDocumentId(uri); String[] split = docId.split(":"); String type = split[0]; Uri contentUri = null; if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } String selection = "_id=?"; String[] selectionArgs = new String[]{split[1]}; return getDataColumn(contentUri, selection, selectionArgs); } } } return null; } private String getFileNameByUri(Uri uri) { String relativePath = getFileRelativePathByUri_API18(uri); if (relativePath == null) relativePath = ""; final String[] projection = { MediaStore.MediaColumns.DISPLAY_NAME }; try (Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null)) { if (cursor != null && cursor.moveToFirst()) { int index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME); return relativePath + cursor.getString(index); } } return null; } private String getFileRelativePathByUri_API18(Uri uri) { final String[] projection; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { projection = new String[]{ MediaStore.MediaColumns.RELATIVE_PATH }; try (Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null)) { if (cursor != null && cursor.moveToFirst()) { int index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.RELATIVE_PATH); return cursor.getString(index); } } } return null; } private String getDataColumn(Uri uri, String selection, String[] selectionArgs) { final String column = MediaStore.Images.Media.DATA; final String[] projection = {column}; try (Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null)) { if (cursor != null && cursor.moveToFirst()) { final int column_index = cursor.getColumnIndexOrThrow(column); return cursor.getString(column_index); } } catch (IllegalArgumentException iae) { iae.printStackTrace(); } return null; } private boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri.getAuthority()); } private boolean isOtherDocument(Uri uri) { // 以/storage开头的也直接返回 if (uri != null && uri.getPath() != null) { String path = uri.getPath(); if (path.startsWith("/storage")) { return true; } if (path.startsWith("/external_files")) { return true; } } return false; } private boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri.getAuthority()); } private boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri.getAuthority()); } }
调用 getFilePathByUri(Uri uri) 即可获得最终的路径。
到此这篇关于Android7.0以上Uri转路径的方法实现(已验证)的文章就介绍到这了,更多相关Android7 Uri转路径内容请搜索靠谱客以前的文章或继续浏览下面的相关文章希望大家以后多多支持靠谱客!
最后
以上就是羞涩鼠标最近收集整理的关于Android7.0以上Uri转路径的方法实现(已验证)的全部内容,更多相关Android7.0以上Uri转路径内容请搜索靠谱客的其他文章。
发表评论 取消回复