【问题标题】:FileNotFoundException open failed: EPERM (Operation not permitted) during saving image file to internal storage on androidFileNotFoundException open failed: EPERM (Operation not allowed) during save image file to internal storage on android
【发布时间】:2020-08-07 22:26:20
【问题描述】:

当我尝试将图像保存到 android 的内部存储时遇到了这个问题。

public static String setImage(Bitmap image) {
    if (image != null) {
        FileOutputStream outputStream = null;
        File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Caramel");
        dir.mkdir();
        String fileName = System.currentTimeMillis() + ".jpg";
        File file = new File(dir, fileName);
        try {
            outputStream = new FileOutputStream(file);
            image.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
            outputStream.flush();
            outputStream.close();
            return fileName;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return null;
}

一切顺利,我可以在调试模式下看到我的位图图像,但还是一样,我得到了下一个错误:

W/System.err: java.io.FileNotFoundException: /storage/emulated/0/Caramel/1587724428205.jpg: open failed: EPERM (Operation not permitted)
    W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:495)
    W/System.err:     at java.io.FileOutputStream.<init>(FileOutputStream.java:235)
    W/System.err:     at java.io.FileOutputStream.<init>(FileOutputStream.java:186)
    W/System.err:     at com.example.caramel.Position.setImage(Position.java:176)
    W/System.err:     at com.example.caramel.PositionActivity.onActivityResult(PositionActivity.java:129)
    W/System.err:     at android.app.Activity.dispatchActivityResult(Activity.java:8300)
    W/System.err:     at android.app.ActivityThread.deliverResults(ActivityThread.java:4905)
    W/System.err:     at android.app.ActivityThread.handleSendResult(ActivityThread.java:4953)
    W/System.err:     at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51)
    W/System.err:     at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    W/System.err:     at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2043)
    W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:106)
    W/System.err:     at android.os.Looper.loop(Looper.java:216)
    W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:7464)
    W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
    W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549)
    W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:955)
    W/System.err: Caused by: android.system.ErrnoException: open failed: EPERM (Operation not permitted)
    W/System.err:     at libcore.io.Linux.open(Native Method)
    W/System.err:     at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
    W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:254)
    W/System.err:     at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
    W/System.err:     at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7360)
    W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:481)
    W/System.err:   ... 17 more

看来,这个原因可能在我的 Manifest.xml 文件中,但我已经设置了这些权限:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

感谢你们的支持,伙计们。

【问题讨论】:

  • 原因是您使用的是Android Q,该路径不可用。
  • 如果您不在 Android Q 上,那么您没有实现运行时权限。

标签: java android file-io


【解决方案1】:

android中的权限系统非常严格,写入内存时必须考虑到这一点 试试这样的:

    public class MainActivity extends AppCompatActivity {
   Button save;
   Bitmap bitmap;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      Drawable drawable = getResources().getDrawable(R.drawable.mario);
      bitmap = ((BitmapDrawable) drawable).getBitmap();
      save = findViewById(R.id.save);
      save.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
            ContextWrapper cw = new ContextWrapper(getApplicationContext());
            File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
            File file = new File(directory, "UniqueFileName" + ".jpg");
            if (!file.exists()) {
               Log.d("path", file.toString());
               FileOutputStream fos = null;
               try {
                  fos = new FileOutputStream(file);
                  bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                  fos.flush();
                  fos.close();
               } catch (java.io.IOException e) {
                  e.printStackTrace();
               }
            }
         }
      });
   }
}

【讨论】:

  • 是的,我已经将我的实现更改为类似的东西并且它有效!谢谢。
  • @Gongelini:你能在这里分享修复吗?
【解决方案2】:

作为临时修复,您可以执行以下操作:在您的 android/app/src/main/AndroidManifest.xml 文件中,位于

<application android:label="APPNAME" android:icon="ICONNAME" ...>

添加android:requestLegacyExternalStorage="true",像这样:

<application android:label="APPNAME" android:icon="ICONNAME" android:requestLegacyExternalStorage="true">

然后它将使用 Android 10 之前的方式请求访问存储空间,因此您仍然可以像以前一样保存文件。

但请注意:在您将应用更新为面向 Android 11(API 级别 30)后,当您的应用在 Android 11 设备上运行时,系统会忽略 requestLegacyExternalStorage 属性,因此您的应用必须准备好支持范围存储并为这些设备上的用户迁移应用数据。请参阅https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage 了解更多信息

【讨论】:

  • 但在我的情况下,应用 targetSdkVersion 是 22。
  • 已经设置 android:requestLegacyExternalStorage=true
【解决方案3】:

在应用程序标签内的应用程序 Manifest.xml 文件中添加以下属性:

android:requestLegacyExternalStorage="true"

最后会是这样的:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:requestLegacyExternalStorage="true">
...
</application>

【讨论】:

  • 已经设置 android:requestLegacyExternalStorage=true
【解决方案4】:

建议改成

        ContextWrapper cw = new ContextWrapper(mContext);
    String fullPath =cw.getExternalFilesDir(Environment.DIRECTORY_MUSIC).toString();
    File directory = cw.getExternalFilesDir(Environment.DIRECTORY_MUSIC);

在这里查看https://www.programmersought.com/article/50766505696/

【讨论】:

    【解决方案5】:

    对我来说,将 compileSdkVersiontargetSdkVersion 都更改为 30 解决了这个问题。

    【讨论】:

      【解决方案6】:

      我有问题 在 android 11 中,文件名中不允许使用“:”。 当您在文件名末尾附加日期时,在末尾添加“:”。 所以只需将所有“:”替换为“。”并且工作正常。

              String fileName = 
                    System.currentTimeMillis().toString().replaceAll(":", ".") + ".jpg";
      
      

      【讨论】:

        【解决方案7】:

        在 android 11 中你可以使用这个模式

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) {
            mPath= getActivity().getExternalFilesDir(Environment.DIRECTORY_DCIM) + "/" + now + ".jpeg";
        }
        else
        {
            mPath= Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpeg";
        }
        

        【讨论】:

        • 谢谢。这对我有用。
        【解决方案8】:

        您可以将照片保存在 DCIM 中,或者在 Android 11 中在其中创建目录,这是一个很好的模式。我遇到了同样的问题,但是在我这样做之后,一切正常。

           if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) {
            Yourpath= getActivity().getExternalFilesDir
            (Environment.DIRECTORY_DCIM) + "/" + nameoffile + ".jpeg";
              }
            else
               {
             
               Yourpath=Environment.getExternalStorageDirectory()
              .toString() + "/" + nameoffile + ".jpeg";
               }
        

        编码愉快!

        【讨论】:

          【解决方案9】:

          您需要在 Android 模拟器上授予权限:

          • 在 Android 模拟器中触摸您的应用 2 秒,
          • 转到应用信息。

          • 转到权限。
          • 选择文件和媒体
          • 允许管理文件。

          【讨论】:

            【解决方案10】:

            从 SDK 版本 30 开始,您不能扩展 android:requestLegacyExternalStorage="true"。而是稍微修改一下 ImageLoader 库。我看到你必须修改你的文件路径:File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Caramel"); 到类似File dir = new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "Caramel"); 的东西。这应该可以解决问题。

            【讨论】:

              猜你喜欢
              • 2022-08-03
              • 1970-01-01
              • 1970-01-01
              • 2021-12-04
              • 2015-09-01
              • 2019-04-04
              • 1970-01-01
              • 1970-01-01
              • 2019-07-24
              相关资源
              最近更新 更多