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(); } }
Advertisement
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.