Skip to content

How to save Tempfile to External storage using ACTION_OPEN_DOCUMENT_TREE?

unable to save the zip file to external storage after picking a folder using ACTION_OPEN_DOCUMENT_TREE.

I’m creating a project which creates and manipulate files and document, in that task I want to save that stuff in external storage but I can’t do that with android developer documentation, so please explain additionally.

I want to save this file

/data/user/0/com.mobilix.docscanner/cache/abc.zip

to

content://com.android.externalstorage.documents/tree/primary%3ADocument

what should I do?

here is my code,

– code for picking a directory to save a file into.

saveBinding.btnInternalStorage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);


                startActivityForResult(intent, PICKER_RESULT);
            }
        });

– Code to be executed after selecting a directory,

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

            if (requestCode == PICKER_RESULT) {

                if (data != null) {
                    Uri uri = data.getData();
                    String path = uri.getPath();
                    Log.d(TAG, "onActivityResult: uri -> " + uri);
                    Log.d(TAG, "onActivityResult: path -> " + path);

                    getContentResolver().takePersistableUriPermission(
                            uri,
                            Intent.FLAG_GRANT_READ_URI_PERMISSION
                    );


                    new BgExecuter().execute(new Runnable() {
                        @Override
                        public void run() {
                            FileManager.saveFile(PDFTools.this,selectedFile, Uri); //selectedFile is that file that is saved by default in the Temp directory
                        }
                    });
                }
            }else {
                Toast.makeText(PDFTools.this, "dome thing happen great", Toast.LENGTH_SHORT).show();
            }
        }
    }

method saveFile

public static void saveFile(Activity context, File selectedFile, Uri uri) {
        context.getContentResolver().getPersistedUriPermissions();

        try {
            InputStream inputStream = context.getContentResolver().openInputStream(Uri.fromFile(selectedFile));
            OutputStream outputStream = context.getContentResolver().openOutputStream(uri);

            // get the content in bytes
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
            byte[] byteArray = new byte[1024];
            BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
            try {
                byte bytes = (byte) bufferedInputStream.read(byteArray);
                if (bytes >= 0) {
                    bufferedOutputStream.write(byteArray, 0, bytes);
                    bufferedOutputStream.flush();
                }
                inputStream.close();
                outputStream.close();
                bufferedOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

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

Answer

So Asking for a file instead of directory to be nicer to the user and lessen overwriting issues.

Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);

// Create a file with the requested MIME type.
intent.setType(mimeType);
// Suggest a filename
intent.putExtra(Intent.EXTRA_TITLE, "abc.zip");
// You can suggest a starting directory here see note about this later
//intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
// OK, this is deprecated and user probably has set their own request code
startActivityForResult(intent, 601);



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

        if (requestCode == 601 && resultCode == RESULT_OK) {
            // The document selected by the user won't be returned in the intent.
            // Instead, a URI to that document will be contained in the return intent
            // provided to this method as a parameter.
            // Pull that URI using resultData.getData().
            Uri uri;
            if (resultData != null) {
                uri = resultData.getData();
                new BgExecuter().execute(new Runnable() {
                        @Override
                        public void run() {
 // Now that the Uri returned is for a file not a directory, your exist "saveFile" method should work
                            copyFileOut(PDFTools.this, selectedFile, Uri);
//selectedFile is that file that is saved by default in the Temp directory
                        }
                    });
            }
        }
    }


private Boolean copyFileOut(Context context,File copyFile, Uri uri){

        BufferedInputStream bis;
        BufferedOutputStream bos = null;

        // Now read the file
        try{
            InputStream input = new FileInputStream(copyFile);
            int originalSize = input.available();

            bis = new BufferedInputStream(input);
            bos = new BufferedOutputStream(context.getContentResolver().openOutputStream(uri));
            byte[] buf = new byte[originalSize];
            //noinspection ResultOfMethodCallIgnored
            bis.read(buf);
            do {
                bos.write(buf);
            } while (bis.read(buf) != -1);
            bis.close();

        } catch (Exception e) {
            if (BuildConfig.LOG) {
                Log.e(Constants.TAG, "copyFileOut:" + e);
            }
            // Notify User of fail
            return false;
        } finally {
            try {
                if (bos != null) {
                    bos.flush();
                    bos.close();
                }
            } catch (Exception ignored) {
            }
        }
        return true;
    }

Note for initial start directory see How I set the ACTION_OPEN_DOCUMENT_TREE start path the first time a user uses my app?

Also note that in your “saveFile” method

InputStream inputStream = context.getContentResolver().openInputStream(Uri.fromFile(selectedFile));

could be replaced with

InputStream inputStream = new FileInputStream(selectedFile);

As you say that this file is in your Apps private Cache directory, so won’t have any permissions problems.