实际上,我使用intent来选择 pdf 文件。我在onActivityResult中得到了uri及其路径(getPath())。
我得到的路径是"content://com.android.providers.downloads.documents/document/2816"
,这不是pdf文件的常用路径。
任何人都可以帮我解决它,以确保提供的uri可以转换为我选择的pdf文件的路径吗?
感谢您的帮助!
答案 0 :(得分:3)
使用以下代码;
Uri uri = intent1.getData();
String selectedFilePath = FilePath.getPath(getActivity(), uri);
像这样定义getPath()
;
public static String getPath(final Context context, final Uri uri) {
// check here to KITKAT or new version
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// 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"),
Long.valueOf(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 the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
和FilePath类由下面的代码定义;
public class FilePath {
/**
* Method for return file path of Gallery image/ Document / Video / Audio
*
* @param context
* @param uri
* @return path of the selected image file from gallery
*/
public static String getPath(final Context context, final Uri uri) {
// check here to KITKAT or new version
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// 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"),
Long.valueOf(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 the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context
* The context.
* @param uri
* The Uri to query.
* @param selection
* (Optional) Filter used in the query.
* @param selectionArgs
* (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
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 index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri
.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri
.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri
.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri
.getAuthority());
}
}
答案 1 :(得分:0)
合并以上答案,您应该尝试捕获方法getDataColumn() cursor.getColumnIndexOrThrow(column)
,否则,将在某些设备中导致IllegalArgumentException
。
Caused by java.lang.IllegalArgumentException: column '_data' does not exist
at android.database.AbstractCursor.getColumnIndexOrThrow + 333(AbstractCursor.java:333)
at android.database.CursorWrapper.getColumnIndexOrThrow + 87(CursorWrapper.java:87)
at com.alo7.android.utils.strings.UriToPathUtil.getDataColumn + 108(UriToPathUtil.java:108)
at com.alo7.android.utils.strings.UriToPathUtil.getPath + 77(UriToPathUtil.java:77)
at com.alo7.android.student.activity.image.ImageControllerActivity.onActivityResult + 241(ImageControllerActivity.java:241)
at android.app.Activity.dispatchActivityResult + 7701(Activity.java:7701)
at android.app.ActivityThread.deliverResults + 5037(ActivityThread.java:5037)
at android.app.ActivityThread.handleSendResult + 5084(ActivityThread.java:5084)
at android.app.ActivityThread.-wrap20(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage + 2053(ActivityThread.java:2053)
at android.os.Handler.dispatchMessage + 108(Handler.java:108)
at android.os.Looper.loop + 166(Looper.java:166)
at android.app.ActivityThread.main + 7529(ActivityThread.java:7529)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run + 245(Zygote.java:245)
at com.android.internal.os.ZygoteInit.main + 921(ZygoteInit.java:921)
为使答案更好。当导致异常时,可以通过复制文件来解决此问题。
public class UriToPathUtil {
/**
* 兼容各种Provider返回的Uri获取真实的文件路径
* 例如:content://media/external/images/media/2617144
* content://com.android.providers.media.documents/document/image%3A11746等
* @param context The context.
* @param uri The Uri to query.
* @author paulburke
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {
final boolean isAboveKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if(isAboveKitKat && 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];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if(isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(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;
}
/**
* Get the value of the data column for this Uri. This is useful for MediaStore Uris, and other
* file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
private static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = MediaStore.Images.Media.DATA;
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if(cursor != null && cursor.moveToFirst()) {
try {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
} catch(IllegalArgumentException exception) {
return getFilePathFromURI(context, uri);
}
}
} finally {
if(cursor != null) cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
// 部分文件可能无法读取到正确的URI 所以复制临时文件作为传输
private static String getFilePathFromURI(Context context, Uri contentUri) {
// copy file and send new file path
String fileName = getFileName(contentUri);
if(!TextUtils.isEmpty(fileName)) {
File copyFile = new File(context.getFilesDir() + File.separator + fileName);
copy(context, contentUri, copyFile);
return copyFile.getAbsolutePath();
}
return null;
}
private static String getFileName(Uri uri) {
if(uri == null) return null;
String fileName = null;
String path = uri.getPath();
if(path == null) return null;
int cut = path.lastIndexOf('/');
if(cut != -1) {
fileName = path.substring(cut + 1);
}
return fileName;
}
private static void copy(Context context, Uri srcUri, File dstFile) {
try {
InputStream inputStream = context.getContentResolver().openInputStream(srcUri);
if(inputStream == null) return;
OutputStream outputStream = new FileOutputStream(dstFile);
copyFile(inputStream, outputStream);
inputStream.close();
outputStream.close();
} catch(IOException e) {
e.printStackTrace();
}
}
private static void copyFile(InputStream inputStream, OutputStream outputStream)
throws IOException {
int BUFFER_SIZE = 1024 * 2;
byte[] buffer = new byte[BUFFER_SIZE];
BufferedInputStream in = new BufferedInputStream(inputStream, BUFFER_SIZE);
BufferedOutputStream out = new BufferedOutputStream(outputStream, BUFFER_SIZE);
int n;
try {
while((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
out.write(buffer, 0, n);
}
out.flush();
} finally {
try {
out.close();
in.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}