Android 写入外部存储

Android write on external Storage

我正在尝试使用以下代码在我的外部存储中写入一些可绘制对象:

Bitmap bm = BitmapFactory.decodeResource( getResources(), R.drawable.paco);

        File file = new File( Environment.getExternalStorageDirectory(), "paco.png");
        FileOutputStream outStream = null;

        try {
        FileOutputStream out = new FileOutputStream(file);
        bm.compress(Bitmap.CompressFormat.PNG, 90, out);
        out.flush();
        out.close();
            Log.d("XXXXX","voy a cerrar");
        } catch (Exception e) {
           Log.e("XXXXX","eeeee", e);
        }

但我不断收到此错误:

28476-28476/com.example.usuari.myapplication3 E/XXXXX: eeeee java.io.FileNotFoundException: /storage/emulated/0/paco.png: open failed: EACCES (Permission denied) at libcore.io.IoBridge.open(IoBridge.java:452) at java.io.FileOutputStream.(FileOutputStream.java:87) at java.io.FileOutputStream.(FileOutputStream.java:72) at com.example.usuari.myapplication3.MainActivity.iniciarDrawables(MainActivity.java:276) at com.example.usuari.myapplication3.MainActivity.onCreate(MainActivity.java:90) at android.app.Activity.performCreate(Activity.java:6876) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3207) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350) at android.app.ActivityThread.access00(ActivityThread.java:222) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:158) at android.app.ActivityThread.main(ActivityThread.java:7229) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied) at libcore.io.Posix.open(Native Method) at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186) at libcore.io.IoBridge.open(IoBridge.java:438) at java.io.FileOutputStream.(FileOutputStream.java:87)  at java.io.FileOutputStream.(FileOutputStream.java:72)  at com.example.usuari.myapplication3.MainActivity.iniciarDrawables(MainActivity.java:276)  at com.example.usuari.myapplication3.MainActivity.onCreate(MainActivity.java:90)  at android.app.Activity.performCreate(Activity.java:6876)  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135)  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3207)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350)  at android.app.ActivityThread.access00(ActivityThread.java:222)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:158)  at android.app.ActivityThread.main(ActivityThread.java:7229)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

我的清单中有权限条目:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.usuari.myapplication3">

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

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

...

编辑:我正在使用 sdk 23

如果您是 API 23+,您必须在运行时请求权限(尽管它们已经存在于清单文件中)。

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)
        != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

        // Show an explanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.

    } else {

        // No explanation needed, we can request the permission.

        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}

Android Sdk >=23 需要用户的运行时权限。仅添加清单权限是行不通的。

试试这个代码:

 if(isPermissionGranted()){
      //open file
    }
 public  boolean isPermissionGranted() {
    if (Build.VERSION.SDK_INT >= 23) {
        if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            Log.v("TAG","Permission is granted");
            return true;
        } else {

            Log.v("TAG","Permission is revoked");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
            return false;
        }
    }
    else { //permission is automatically granted on sdk<23 upon installation
        Log.v("TAG","Permission is granted");
        return true;
    }
}

捕获权限结果:

 @Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {

        case 0: {

            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(getApplicationContext(), "Permission granted", Toast.LENGTH_SHORT).show();
                //call your method open file
            } else {
                Toast.makeText(getApplicationContext(), "Permission denied", Toast.LENGTH_SHORT).show();
            }
            return;
        }
    }
 }

首先,检查您的存储是否准备就绪:

if (Environment.getExternalStorageState(file) != Environment.MEDIA_MOUNTED) {
    // your storage is not ready for work, do something with this
}

其次,据我所知,从 Kit-Kat 开始,您无法写入外部存储的根目录。 只允许写入存储上的应用程序特定文件夹。 要获取此文件夹,请使用

Environment.getExternalStoragePublicDirectory(directoryType);

directoryType 怎么样,检查方法的文档,您可能想要使用 Environment.DIRECTORY_PICTURES。

试试这个。