如何在Android中的可移动媒体上获取对DCIM目录的写入权限?

时间:2017-02-04 13:33:31

标签: android permissions

我的代码如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        writeFile();
    }



    public void writeFile()  {

        File removableRoot = RootsUtil.getRemovableRoots(this)[0];
        File DCIMDirectory = new File(removableRoot, "DCIM");
        File cameraDirectory = new File(DCIMDirectory, "Camera");

        if( cameraDirectory.exists() ) {
            try {
                String filename = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date()) + ".txt";


                //cameraDirectory.mkdirs();
                File file = new File(cameraDirectory, filename);
                FileWriter writer = null;

                writer = new FileWriter(file);
                PrintWriter printWriter = new PrintWriter(writer);
                printWriter.println("Hello World");

                printWriter.close();
                writer.close();

                System.out.println("Number of files: " + cameraDirectory.listFiles().length);

            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
如果且存在,

cameraDirectory等于/storage/9C33-6BBD/DCIM/Camera。这是我的Camera应用程序存储它的文件。

我也试图将文件写入此目录,但失败并出现以下异常:

java.io.FileNotFoundException: /storage/9C33-6BBD/DCIM/Camera/20170204_192001.txt: open failed: EACCES (Permission denied)
    at libcore.io.IoBridge.open(IoBridge.java:452)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
    at java.io.FileWriter.<init>(FileWriter.java:42)
    at com.inthemoon.trycamerawrite.MainActivity.writeFile(MainActivity.java:48)
    at com.inthemoon.trycamerawrite.MainActivity.onCreate(MainActivity.java:28)
    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.access$1100(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)
    ... 17 more

显然,我无权写入此目录。如何获得此权限?

更新

我已按以下方式修改了代码:

private static final int RQS_OPEN_DOCUMENT_TREE = 2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE, Uri.fromFile(cameraDirectory));
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
        startActivityForResult(intent, RQS_OPEN_DOCUMENT_TREE);

        //writeFile();
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        writeFile();
    }

然后允许用户手动选择DCIM/Camera,这无济于事。

1 个答案:

答案 0 :(得分:1)

您正在尝试直接写入可移动存储的文件系统。除了您的应用独有的精选目录(例如<div> <div style="display: block"> <canvas baseChart [datasets]="barChartData" [labels]="barChartLabels" [options]="barChartOptions" [legend]="barChartLegend" [chartType]="barChartType" (chartHover)="chartHovered($event)" (chartClick)="chartClicked($event)"></canvas> <div align="center">{{barChartTitle}}</div> </div> </div> 返回的目录)之外,这不起作用。

使用getExternalFilesDirs()并不会神奇地授予您文件系统访问权限。 所做的是为您提供一个ACTION_OPEN_DOCUMENT_TREE,您可以与UriContentResolver和kin一起使用DocumentFile来处理基于文档和集合的内容在Uri上。

ACTION_OPEN_DOCUMENT_TREEthe storage access framework的一部分,在文档中有介绍。

Android 7.0+还提供了scoped directory access,它为用户提供了一种更简单的方式,允许您访问可移动存储上的DCIM/。但是,它也会为您提供Uri,您仍然会使用ContentResolverDocumentFile等来处理基于Uri的内容和集合。