在由Intent.ACTION_OPEN_DOCUMENT_TREE返回的目录中创建新文件。

10
在我的应用程序中,用户可以使用隐式意图 ACTION_OPEN_DOCUMENT_TREE 来选择要创建 Excel 文件的目录。然而,在 onActivityResult() 中返回的 Uri 不能被 FileOutputStream() 使用,它会抛出 FileNotFoundException 异常。
java.io.FileNotFoundException: content:/com.android.externalstorage.documents/tree/home%3A:test.xlsx (No such file or directory)

onActivityResult()中,我通过File.exists()检查路径是否存在,如果不存在,我想创建一个新的Excel文件。

onActivityResult():

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        Log.d(TAG, "onActivityResult: called");
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK && requestCode == 2) {
            Log.d(TAG, "onActivityResult: path = " + data.getData()
                                                         .getPath());
            Uri treePath = data.getData();
            File path = new File(treePath + File.pathSeparator + "test.xlsx");
            if (path.exists()) {
                updateExistingExcelFile(path);
            } else {
                createNewExcelFile(path);
            }
        }
    }

createNewExcelFile():

    private void createNewExcelFile(File path) {
        Log.d(TAG, "createNewExcelFile: called");
        Workbook workbook = new HSSFWorkbook();
        Cell cell;
        Sheet sheet;
        sheet = workbook.createSheet("Name of sheet");
        Row row = sheet.createRow(0);
        cell = row.createCell(0);
        cell.setCellValue("Name");
        cell = row.createCell(1);
        cell.setCellValue("Number");
        sheet.setColumnWidth(0, (10 * 200));
        sheet.setColumnWidth(1, (10 * 200));
        FileOutputStream fileOutputStream;
        try {
            fileOutputStream = new FileOutputStream(path);
            workbook.write(fileOutputStream);
            Toast.makeText(this, "Created", Toast.LENGTH_LONG)
                 .show();
            fileOutputStream.close();
        } catch (IOException e) {
            Log.e(TAG, "createNewExcelFile: ", e);
        }
    }

如果我使用Activity.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)或类似的内容来替换隐式意图路径,这段代码就能正常运行。

1
不要尝试将URI转换为真实路径,请参见 https://stackoverflow.com/q/26972539/2373819。 - Andrew
1个回答

23

步骤1:获取ACTION_OPEN_DOCUMENT_TREE返回的Uri,并将其传递给DocumentFile.fromTreeUri()方法。

步骤2:在该DocumentFile上调用createFile()方法,以获取表示子文档的DocumentFile

步骤3:在步骤2中创建的DocumentFile上调用getUri()方法

步骤4:在ContentResolver上调用openOutputStream()方法,并传入步骤3中的Uri,以获取可以用于写入内容的OutputStream。您可以通过在某些上下文(例如Activity)上调用getContentResolver()方法来获取ContentResolver

查看此博客文章了解有关使用ACTION_OPEN_DOCUMENT_TREE的更多信息。


谢谢,文件已经创建。但是我遇到了一个“SecurityException”异常:“java.lang.SecurityException: No persistable permission grants found for UID 10207 and Uri content://com.android.externalstorage.documents/tree/home:/document/home:test.xlsx [user 0]”。在“onActivityResult()”中,我调用了“getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)”来获取持久化的URI权限,然后我调用了“createNewExcelFile(uri)”函数。 - René Jörg Spies
1
我通过删除对“takePersistableUriPersmission()”的调用来解决了问题,现在它完美地工作了。谢谢你的帮助。 - René Jörg Spies

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接