Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

FileNotFoundException open failed: EPERM (Operation not permitted) during saving image file to internal storage on android

Ask Question

I faced this problem when I tried to save the image to internal storage on 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;

All goes nice and well, and I can see my Bitmap image in debug mode, but all the same, i get the next error:

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

It seems, that reason could be in my Manifest.xml file, but i've already set these permissions:

<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" />

Thanks for your support, guys.

I am seeing this error under Android 12. I can copy an M3U8 playlist file to the public DCIM folder from my APK asset folder in my app. So I can create the file OK. However when I try to append updated MP4 entries to the playlist (which I have created in the DCIM folder) the OS then creates the exception because of the file extension "M3U8" which is not a typical file extension to be found in the DCIM folder. So I believe the OS is policing public folders according to file type/extension. – Peter Nov 4, 2022 at 19:27

I got the issue In android 11 ":" is not allowed in file name. And when you append date at the end of file name its add ":" at the end. so just replace all ":" with "." and its working fine.

        String fileName = 
              System.currentTimeMillis().toString().replaceAll(":", ".") + ".jpg";
                I have a similar issue with the file name "?.txt" in Android 12 API 31. I can store it locally in my app (SFTP Server s0 v1) directory "/data/data/ch.becke.sftp_server__s0_v1/files" but when I store it on the external storage directory "/storage/emulated/0/Download" I get this error "android.system.ErrnoException: open failed: EPERM (Operation not permitted)". Other file names are no problem. Do you have evidence which file name characters are allowed in which Android Version?
– becke-ch
                Sep 15, 2022 at 16:00

As a temporary fix you could do: In your android/app/src/main/AndroidManifest.xml file, at

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

add android:requestLegacyExternalStorage="true", like so:

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

It will then use the pre-Android 10 way of requesting access to storage, so you can still save your file as you could earlier.

But caution: After you update your app to target Android 11 (API level 30), the system ignores the requestLegacyExternalStorage attribute when your app is running on Android 11 devices, so your app must be ready to support scoped storage and to migrate app data for users on those devices. See https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage for more info

Very important: "But caution: After you update your app to target Android 11 (API level 30)" – vrunoa Mar 26, 2022 at 18:52

The permission system in android is very strict, you must take this into account when writing to internal memory Try something like this:

    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();

In android 11 you can use this pattern

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

Add the following attribute in your app's Manifest.xml file inside the application tag:

android:requestLegacyExternalStorage="true"

Finally, it will look like this:

<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>

I would suggest to change it to

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

check it here https://www.programmersought.com/article/50766505696/

you need to grant permission on the Android emulator:

  • touch your app in Android Emulator 2 seconds,
  • go to app info.
  • go to permissions.
  • select Files and media
  • Allow management files.
  • You can save photos in DCIM or create a directory in it in Android 11, which is a good pattern. I'm having the same problem, however after I do this, everything works fine.

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

    Happy Coding!

    Starting with SDK version 30, you can NOT extend android:requestLegacyExternalStorage="true". Instead modify you ImageLoader library a little. I see you have to modify you file path: File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Caramel"); into something like File dir = new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "Caramel");. This should do a trick.

    This worked for me: MANAGE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE

    in file pubspec.yaml

    dependencies:
      flutter:
        sdk: flutter
      http: ^0.13.4
      permission_handler: ^9.0.2
      flutter_downloader: ^1.5.2
      path_provider: ^2.0.9
      external_path: ^1.0.1
    

    in file AndroidManifest.xml

    <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
    <application
            android:label="ejemplo_test"
            android:usesCleartextTraffic="true"
            android:icon="@mipmap/ic_launcher"
            android:requestLegacyExternalStorage="true">
    <provider
               android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider"
               android:authorities="${applicationId}.flutter_downloader.provider"
               android:exported="false"
               android:grantUriPermissions="true">
               <meta-data
                   android:name="android.support.FILE_PROVIDER_PATHS"
                   android:resource="@xml/provider_paths"/>
           </provider>
    

    in file main.dart

        void main() async{
          WidgetsFlutterBinding.ensureInitialized();
          await FlutterDownloader.initialize(
              debug: true
          runApp(const MyApp());
        class _MyHomePageState extends State<MyHomePage> {
          String localPath = "";
          int progress = 0;
          ReceivePort _port = ReceivePort();
        @override
          void initState(){
            super.initState();
            initPlatformState();
            IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port');
            _port.listen((dynamic data) {
              String id = data[0];
              DownloadTaskStatus status = data[1];
              int progress = data[2];
              setState((){ });
            FlutterDownloader.registerCallback(downloadCallback);
            _requestPermissions();
    @override
      void dispose() {
        IsolateNameServer.removePortNameMapping('downloader_send_port');
        super.dispose();
      static void downloadCallback(String id, DownloadTaskStatus status, int progress) {
        final SendPort? send = IsolateNameServer.lookupPortByName('downloader_send_port');
        send?.send([id, status, progress]);
    Future<void> initPlatformState() async {
        final path = await ExternalPath.getExternalStorageDirectories();
        setState(() {
          localPath = path[0].toString()+"/Android/media/NameAPP";
        log("path: ${localPath}");
        final savedDir = Directory(localPath);
        bool hasExisted = await savedDir.exists();
        if (!hasExisted) {
          savedDir.create(recursive: true);
    SaveImages(String url,String name) async{
        log("url: ${url}");
        log("name: ${name}");
        final id = await FlutterDownloader.enqueue(
          url:"${url}",
          savedDir: localPath,
          fileName: name.toString(),
          showNotification: true,
          openFileFromNotification: true,
    Future<void> _requestPermissions() async {
        Map<Permission, PermissionStatus> statuses = await [
          Permission.storage,
          Permission.manageExternalStorage
        ].request();
        log("statuses: ${statuses}");
        if (statuses == PermissionStatus.granted) {
          //createFolder("TiendaOnline");
          MensajeToast("Permission granted.",Colors.green);
        } else if (statuses == PermissionStatus.denied) {
          MensajeToast("Denied. Show a dialog with a reason and again ask for the permission.",Colors.red);
        } else if (statuses == PermissionStatus.permanentlyDenied) {
          MensajeToast("Take the user to the settings page.",Colors.red);
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.