java 找不到文件异常(来自 URI 的路径)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36329379/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 01:17:15  来源:igfitidea点击:

File not found exception (Path from URI)

javaandroidandroid-intentfileinputstream

提问by Riptyde4

I'm trying to get a FileInputStreamobject for the picture a user selects from their gallery and when I'm trying to open the file from the URI I receive, it keeps saying FileNotFoundException...

我正在尝试为FileInputStream用户从他们的图库中选择的图片获取一个对象,当我尝试从收到的 URI 打开文件时,它一直说FileNotFoundException...

Here's the code I'm using to fire off the intent for picking an image from the gallery:

这是我用来激发从图库中选择图像的意图的代码:

Intent intent = new Intent();
    intent.setType("image/*");
    intent.setAction(Intent.ACTION_GET_CONTENT);
    startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_REQUEST);

And here's the code I use for catching onActivityResult:

这是我用于捕获的代码onActivityResult

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {

        Uri uri = data.getData();
        File myFile = new File(uri.getPath());
        FileInputStream fiStream = new FileInputStream(myFile);
        ...
    }

}

Right on the creation of the FileInputStream, I get the folloiwng error upon choosing one of my photos via the emulator:

就在创建 时FileInputStream,通过模拟器选择我的一张照片时出现以下错误:

W/System.err: java.io.FileNotFoundException: /document/image:26171: open failed: ENOENT (No such file or directory)

Maybe I'm retrieving the file from the URI incorrectly??? Any help here would be greatly appreciated, thanks!!

也许我从 URI 中错误地检索了文件???任何帮助在这里将不胜感激,谢谢!!

Solution

解决方案

I ended up using https://android-arsenal.com/details/1/2725It's very easy to use!

我最终使用了https://android-arsenal.com/details/1/2725非常好用!

回答by Napster Scofield

I had the exact same issue.

我有完全相同的问题。

My problemI was using this code

我的问题我正在使用此代码

        @Override
            public void onActivityResult(int requestCode, int resultCode, Intent data) {
                super.onActivityResult(requestCode, resultCode, data);

                if(requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null){
                    Uri uri = data.getData();
                    try {
                        Bitmap bitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), uri);

until when I found out it could not handle a bigger image. I had to change and use another method to get the image.

直到我发现它无法处理更大的图像。我不得不改变并使用另一种方法来获取图像。

Using InputStream

使用输入流

            File file= new File(uri.getPath());
            FileInputStream inputStream= new FileInputStream(file);

This gives a file not found exception for the path format is the reason

这给出了路径格式的文件未找到异常的原因

As Knossos said

正如克诺索斯所说

"The Uri that you are attempting to open is content://document/image:26171. You need to access it with a ContentProvider

“您尝试打开的 Uri 是 content://document/image:26171。您需要使用 ContentProvider 访问它

Thanks to Paul Burke with his library aFileChooser http://github.com/iPaulPro/aFileChooser

感谢 Paul Burke 和他的图书馆 aFileChooser http://github.com/iPaulPro/aFileChooser

To make it simple just create a class I called it FileChooser.java

为了简单起见,只需创建一个我称之为FileChooser.java的类

        import android.content.ContentUris;
        import android.content.Context;
        import android.database.Cursor;
        import android.net.Uri;
        import android.os.Build;
        import android.os.Environment;
        import android.provider.DocumentsContract;
        import android.provider.MediaStore;


        public class FileChooser {

            /**
             * Get a file path from a Uri. This will get the the path for Storage Access
             * Framework Documents, as well as the _data field for the MediaStore and
             * other file-based ContentProviders.
             *
             * @param context The context.
             * @param uri The Uri to query.
             * @author paulburke
             */
            public static String getPath(final Context context, final Uri uri) {

                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];
                        }

                        // 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.
             */
            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);
                    }
                } 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());
            }
        }

Then we can simply access it in our activity result

然后我们可以简单地在我们的活动结果中访问它

        @Override
            public void onActivityResult(int requestCode, int resultCode, Intent data) {
                super.onActivityResult(requestCode, resultCode, data);

                if(requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null){
                    Uri uri = data.getData();
                    try {
                        InputStream in = new FileInputStream(FileChooser.getPath(getContext(),uri));

As I wanted to resize the image before using it there is the full code... I hope it helps someone...;) Thanks to blubl

因为我想在使用之前调整图像大小,所以有完整的代码......我希望它可以帮助某人......;)感谢 blubl

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if(requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null){
        Uri uri = data.getData();
        try {
            /*Bitmap bitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), uri);*/

            InputStream in = new FileInputStream(FileChooser.getPath(getContext(),uri));

            int dstWidth = 1980;
            int dstHeight = 960;
            int inWidth, inHeight;

            //get image size
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(in, null, options);
            in.close();

            inWidth = options.outWidth;
            inHeight = options.outHeight;

            in = new FileInputStream(FileChooser.getPath(getContext(),uri));
            options = new BitmapFactory.Options();
            // decode full image pre resized
            options.inSampleSize = Math.max(inWidth/dstWidth, inHeight/dstHeight);

            Bitmap roughtBitmap = BitmapFactory.decodeStream(in, null, options);

            Matrix m = new Matrix();
            RectF inRect = new RectF(0, 0, roughtBitmap.getWidth(), roughtBitmap.getHeight());
            RectF outRectF = new RectF(0, 0, dstWidth, dstHeight);
            m.setRectToRect(inRect, outRectF, Matrix.ScaleToFit.CENTER);
            float[] values = new float[9];
            m.getValues(values);

            Bitmap resizedBitmap = Bitmap.createScaledBitmap(roughtBitmap, (int)(roughtBitmap.getWidth() * values[0]), (int)(roughtBitmap.getHeight() * values[4]), true);

            currentQrItem.setPicture(resizedBitmap);
            adapter.changeImage(currentQrItem);
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

回答by Pavya

Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                    intent.setType("image/*");
                    startActivityForResult(Intent.createChooser(intent, "Select File"), SELECT_FILE);

// in onactivity result

// 在 onactivity 结果中

Uri selectedImageUri = data.getData();
                String[] projection = { MediaStore.MediaColumns.DATA };
                CursorLoader cursorLoader = new CursorLoader(this,selectedImageUri, projection, null, null,null);
                Cursor cursor =cursorLoader.loadInBackground();
                int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
                cursor.moveToFirst();
                String selectedImagePath = cursor.getString(column_index);

                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                final int REQUIRED_SIZE = 200;
                int scale = 1;
                while (options.outWidth / scale / 2 >= REQUIRED_SIZE
                        && options.outHeight / scale / 2 >= REQUIRED_SIZE)
                    scale *= 2;
                options.inSampleSize = scale;
                options.inJustDecodeBounds = false;
                Bitmap bitmap = BitmapFactory.decodeFile(selectedImagePath, options);

回答by Knossos

The issue here is that you are attempting to access a content Uri as though it were a File.

这里的问题是您试图访问一个内容 Uri,就好像它是一个文件一样。

The Uri that you are attempting to open is content://document/image:26171. You need to access it with a ContentProvider.

您尝试打开的 Uri 是content://document/image:26171. 您需要使用ContentProvider.

An example to do so can be found with this great Stack Overflow answer.

可以在这个很棒的Stack Overflow 答案中找到这样做的示例。

回答by Thahaseen

Are you targeting 23 sdk version? If so, you must get runtime permission for READ_EXTERNAL_STORAGE.

您的目标是 23 sdk 版本吗?如果是这样,您必须获得 READ_EXTERNAL_STORAGE 的运行时权限。