无法通过uri打开下载的文件

时间:2017-08-04 09:46:15

标签: android uri

实际上,我使用intent来选择 pdf 文件。我在onActivityResult中得到了uri及其路径(getPath())。 我得到的路径是"content://com.android.providers.downloads.documents/document/2816",这不是pdf文件的常用路径。

任何人都可以帮我解决它,以确保提供的uri可以转换为我选择的pdf文件的路径吗?

感谢您的帮助!

2 个答案:

答案 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();
        }
    }
}

}