在Android 10(Q)中使用SAF File Picker将文件从下载复制到本地应用程序文件夹

时间:2019-11-17 09:24:12

标签: java android

从Android 10(API 29)开始,我需要使用Storage Access Framework的文件选择器选择GPX(GPS)文件,以将其从“下载”文件夹复制到本地应用程序文件夹。我已经实现了文件选择器并能够选择GPX文件,但是结果数据URI看起来与文件名不同(但唯一),而且我似乎无法使用它来复制文件。其余代码与我在先前版本的Android中使用的“复制”代码相同。我在做什么错,我该如何最好地使用SAF File Picker复制文件?我在网上找不到最近的(API 29)“文件副本”示例...

private static final int READ_REQUEST_CODE = 42;
...
public void performFileSearch() {         
                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);       
                intent.addCategory(Intent.CATEGORY_OPENABLE);
                // intent.setType("application/gpx");   // Filters GPX file but wont let me select them.
                intent.setType("*/*");
                startActivityForResult(intent, READ_REQUEST_CODE);
            }
...
if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
            Uri uri = null;
            if (data != null) {
                uri = data.getData();
                handleDownloadedGPXFiles2(uri);
            }
        }
...
private void handleDownloadedGPXFiles2(Uri selectedFileUri) {
        File sourceFile = new File(selectedFileUri.getPath());     // Returns a unique number or string but NOT filename string???
        File destDirectory = new File(this.getExternalFilesDir(null), "Imported");
        File destFile = new File(destDirectory, "test.gpx");       // Needs to be same name as original filename.
        try {
            if (!destFile.exists()) {
                destFile.createNewFile();
            }
            FileInputStream inStream = new FileInputStream(sourceFile);
            FileOutputStream outStream = new FileOutputStream(destFile);
            FileChannel inChannel = inStream.getChannel();
            FileChannel outChannel = outStream.getChannel();
            inChannel.transferTo(0, inChannel.size(), outChannel);
            inStream.close();
            outStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Toast.makeText(getApplicationContext(), "File Import Complete", Toast.LENGTH_LONG).show();
   }

2 个答案:

答案 0 :(得分:1)

File sourceFile = new File(selectedFileUri.getPath());    

移至上方。

FileInputStream inStream = new FileInputStream(sourceFile);

用以下方式替换该行:

InputStream inStream = getContentResolver().openInputStream(selectedFileUri);

您还可以删除

       if (!destFile.exists()) {
            destFile.createNewFile();
        }

该文件将由new FileOutputStream();

创建

最后:您的最后一个Toast()在错误的位置。它应该在try块中。

在catch块中放置一个不同的Toast()来告知您自己或用户。

答案 1 :(得分:0)

感谢blackapps。最终代码效果很好...

    private void handleDownloadedGPXFiles2(Uri selectedFileUri) {

        String displayName = "imported.gpx";
        String fileExtension;
        ContentResolver contentResolver = getContentResolver();
        Cursor cursor = contentResolver.query(selectedFileUri, null, null, null, null);
                try {
                    if (cursor != null && cursor.moveToFirst()) {
                        displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
                        if (displayName != null && displayName.length() >=4) {
                            fileExtension = displayName.substring(displayName.length() - 4);
                            if (!fileExtension.equals(".gpx")){
                                myCustomToast("Must be a .GPX file!");
                                return;
                            }
                        } else {
                                myCustomToast("Must be a .GPX file!");
                                return;
                        }
                    }
                    File destDirectory = new File(this.getExternalFilesDir(null), "Imported");
                    File destFile = new File(destDirectory, displayName);
                    FileOutputStream outStream = new FileOutputStream(destFile);
                    InputStream in = getContentResolver().openInputStream(selectedFileUri);
                    OutputStream out = outStream;
                    byte[] buffer = new byte[1024];
                    int read;
                    while ((read = in.read(buffer)) != -1) {
                        out.write(buffer, 0, read);
                    }
                    in.close();
                    out.flush();
                    out.close();
                    Toast.makeText(getApplicationContext(), "File Import Complete", Toast.LENGTH_LONG).show();
                } catch (IOException e) {
                    Toast.makeText(getApplicationContext(), "File Import FAILED", Toast.LENGTH_LONG).show();
                    e.printStackTrace();
                }
                finally
                {
                    if (cursor != null)
                        cursor.close();
                }
    }