FileNotFoundException open failed: EPERM (Operation not allowed) 在将图像文件保存到 Android 上的内部存储期间

Gon*_*ini 14 java file-io android

当我尝试将图像保存到 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

看来,这个原因可能在我的 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" />
Run Code Online (Sandbox Code Playgroud)

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

小智 38

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

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

Run Code Online (Sandbox Code Playgroud)


Rog*_*ier 11

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

<application android:label="APPNAME" android:icon="ICONNAME" ...>
Run Code Online (Sandbox Code Playgroud)

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

<application android:label="APPNAME" android:icon="ICONNAME" android:requestLegacyExternalStorage="true">
Run Code Online (Sandbox Code Playgroud)

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

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


Muh*_*asi 8

在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";
}
Run Code Online (Sandbox Code Playgroud)


小智 6

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();
               }
            }
         }
      });
   }
}
Run Code Online (Sandbox Code Playgroud)


Raz*_*azz 6

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

android:requestLegacyExternalStorage="true"
Run Code Online (Sandbox Code Playgroud)

最后,它看起来像这样:

<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>
Run Code Online (Sandbox Code Playgroud)

  • 已经设置 android:requestLegacyExternalStorage=true (3认同)

Meh*_*Far 6

我建议将其更改为

        ContextWrapper cw = new ContextWrapper(mContext);
    String fullPath =cw.getExternalFilesDir(Environment.DIRECTORY_MUSIC).toString();
    File directory = cw.getExternalFilesDir(Environment.DIRECTORY_MUSIC);
Run Code Online (Sandbox Code Playgroud)

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


mr *_*oob 5

显然,如果您尝试保存到 Android 11 的内部存储,则无法保存在 /storage/emulated/0 中。仅限于公共文件夹,如“下载”、“文档”等。至少对我来说是这样。