javaandroidfileioexceptionruntime-permissions

File.createNewFile() method throws exception in Android M


I have a problem to create file in Android M.

I use Nexus 9 with Android 6.0.1. Then I set in my project as below:

AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

build.gradle

android {
    defaultConfig {
        targetSdkVersion 23
        ...
    }
}

MainActivity.Java

public class MainActivity extends AppCompatActivity {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    String storagePath = Environment.getExternalStorageDirectory().getAbsolutePath();
    String rootPath = storagePath + "/test";
    String fileName = "/test.zip";

    File root = new File(rootPath);
    if(!root.mkdirs()) {
        Log.i("Test", "This path is already exist: " + root.getAbsolutePath());
    }

    File file = new File(rootPath + fileName);
    try {
        if (!file.createNewFile()) {
            Log.i("Test", "This file is already exist: " + file.getAbsolutePath());
        }

    } catch (Exception e) {
        e.printStackTrace();
    }
}

Build was success and application was launched, but I got exception message like this:

IOExceiption

01-07 18:13:40.669 18027-18027/com.sample.myapplication W/System.err: java.io.IOException: open failed: ENOENT (No such file or directory)
01-07 18:13:40.669 18027-18027/com.sample.myapplication W/System.err:     at java.io.File.createNewFile(File.java:939)
01-07 18:13:40.669 18027-18027/com.sample.myapplication W/System.err:     at com.sample.myapplication.MainActivity.onCreate(MainActivity.java:36)
01-07 18:13:40.670 18027-18027/com.sample.myapplication W/System.err:     at android.app.Activity.performCreate(Activity.java:6251)
01-07 18:13:40.670 18027-18027/com.sample.myapplication W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
01-07 18:13:40.670 18027-18027/com.sample.myapplication W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
01-07 18:13:40.670 18027-18027/com.sample.myapplication W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
01-07 18:13:40.670 18027-18027/com.sample.myapplication W/System.err:     at android.app.ActivityThread.-wrap11(ActivityThread.java)
01-07 18:13:40.671 18027-18027/com.sample.myapplication W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
01-07 18:13:40.671 18027-18027/com.sample.myapplication W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
01-07 18:13:40.671 18027-18027/com.sample.myapplication W/System.err:     at android.os.Looper.loop(Looper.java:148)
01-07 18:13:40.671 18027-18027/com.sample.myapplication W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5417)
01-07 18:13:40.671 18027-18027/com.sample.myapplication W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
01-07 18:13:40.671 18027-18027/com.sample.myapplication W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
01-07 18:13:40.671 18027-18027/com.sample.myapplication W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
01-07 18:13:40.671 18027-18027/com.sample.myapplication W/System.err: Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
01-07 18:13:40.671 18027-18027/com.sample.myapplication W/System.err:     at libcore.io.Posix.open(Native Method)
01-07 18:13:40.671 18027-18027/com.sample.myapplication W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
01-07 18:13:40.671 18027-18027/com.sample.myapplication W/System.err:     at java.io.File.createNewFile(File.java:932)
01-07 18:13:40.671 18027-18027/com.sample.myapplication W/System.err:   ... 13 more

How can I solve this problem? I don't catch what I miss....

Please help.


Solution

  • Updated

    Replace storagePath to access scoped storage, for Android 10.

    Refer this document for more detail.


    Thanks, laalto.

    I didn't know about runtime permission.

    I solved exception like this:

    MainActivity.java

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            /* Request user permissions in runtime */
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[] {
                            Manifest.permission.READ_EXTERNAL_STORAGE,
                            Manifest.permission.WRITE_EXTERNAL_STORAGE
                    },
                    100);
            /* Request user permissions in runtime */
    
            createTestFile();
        }
    
        @TargetApi(23)
        @Override
        public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
            switch (requestCode) {
                case 100:
                    if (grantResults.length > 0
                            && grantResults[0] == PackageManager.PERMISSION_GRANTED
                            && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                        // User checks permission.
    
                    } else {
                        Toast.makeText(MainActivity.this, "Permission is denied.", Toast.LENGTH_SHORT).show();
                        finish();
                    }
            }
        }
    
        private void createTestFile() {
            // String storagePath = Environment.getExternalStorageDirectory().getAbsolutePath();
    
            // If Target API level is 29(Android 10),
            // you should access local path in scoped storage mode.
            File localStorage = getExternalFilesDir(null);
            if (localStorage == null) { return; }
            String storagePath = localStorage.getAbsolutePath();
            String rootPath = storagePath + "/test";
            String fileName = "/test.zip";
    
            File root = new File(rootPath);
            if(!root.mkdirs()) {
                Log.i("Test", "This path is already exist: " + root.getAbsolutePath());
            }
    
            File file = new File(rootPath + fileName);
            try {
                int permissionCheck = ContextCompat.checkSelfPermission(
                        MainActivity.this,
                        android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
                if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
                    if (!file.createNewFile()) {
                        Log.i("Test", "This file is already exist: " + file.getAbsolutePath());
                    }
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    It works!