Save file android java

Android: save a file from an existing URI

How to save a media file (say .mp3) from an existing URI, which I am getting from an Implicit Intent?

I am getting URI from the intent Uri mediaUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);

10 Answers 10

void savefile(URI sourceuri) < String sourceFilename= sourceuri.getPath(); String destinationFilename = android.os.Environment.getExternalStorageDirectory().getPath()+File.separatorChar+"abc.mp3"; BufferedInputStream bis = null; BufferedOutputStream bos = null; try < bis = new BufferedInputStream(new FileInputStream(sourceFilename)); bos = new BufferedOutputStream(new FileOutputStream(destinationFilename, false)); byte[] buf = new byte[1024]; bis.read(buf); do < bos.write(buf); >while(bis.read(buf) != -1); > catch (IOException e) < e.printStackTrace(); >finally < try < if (bis != null) bis.close(); if (bos != null) bos.close(); >catch (IOException e) < e.printStackTrace(); >> > 

on the Android 5.x (Lollipop), must include: — Create empty file for ‘destinationFilename’ before using FileOutputStream to avoid throw IOException!

This works just because sourceuri looks like file:///something and points to a file. This is no longer possible since API 24 (sharing file Uris between processes/apps is porhibited). Always use ContentResolver to open content Uris.

If Uri is received from Google Drive, it can be a Virtual File Uri too. Check this article from CommonsWare for more information. So you have to consider that condition too while saving file from Uri.

To find if file Uri is virtual or not you can use

private static boolean isVirtualFile(Context context, Uri uri) < if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) < if (!DocumentsContract.isDocumentUri(context, uri)) < return false; >Cursor cursor = context.getContentResolver().query( uri, new String[], null, null, null); int flags = 0; if (cursor.moveToFirst()) < flags = cursor.getInt(0); >cursor.close(); return (flags & DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT) != 0; > else < return false; >> 

You can get the stream data from this virtual file like this:

private static InputStream getInputStreamForVirtualFile(Context context, Uri uri, String mimeTypeFilter) throws IOException < ContentResolver resolver = context.getContentResolver(); String[] openableMimeTypes = resolver.getStreamTypes(uri, mimeTypeFilter); if (openableMimeTypes == null || openableMimeTypes.length < 1) < throw new FileNotFoundException(); >return resolver .openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null) .createInputStream(); > 

For finding MIME type try

private static String getMimeType(String url) < String type = null; String extension = MimeTypeMap.getFileExtensionFromUrl(url); if (extension != null) < type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); >return type; > 
public static boolean saveFile(Context context, String name, Uri sourceuri, String destinationDir, String destFileName) < BufferedInputStream bis = null; BufferedOutputStream bos = null; InputStream input = null; boolean hasError = false; try < if (isVirtualFile(context, sourceuri)) < input = getInputStreamForVirtualFile(context, sourceuri, getMimeType(name)); >else < input = context.getContentResolver().openInputStream(sourceuri); >boolean directorySetupResult; File destDir = new File(destinationDir); if (!destDir.exists()) < directorySetupResult = destDir.mkdirs(); >else if (!destDir.isDirectory()) < directorySetupResult = replaceFileWithDir(destinationDir); >else < directorySetupResult = true; >if (!directorySetupResult) < hasError = true; >else < String destination = destinationDir + File.separator + destFileName; int originalsize = input.available(); bis = new BufferedInputStream(input); bos = new BufferedOutputStream(new FileOutputStream(destination)); byte[] buf = new byte[originalsize]; bis.read(buf); do < bos.write(buf); >while (bis.read(buf) != -1); > > catch (Exception e) < e.printStackTrace(); hasError = true; >finally < try < if (bos != null) < bos.flush(); bos.close(); >> catch (Exception ignored) < >> return !hasError; > private static boolean replaceFileWithDir(String path) < File file = new File(path); if (!file.exists()) < if (file.mkdirs()) < return true; >> else if (file.delete()) < File folder = new File(path); if (folder.mkdirs()) < return true; >> return false; > 

Call this method from an AsycTask. Let me know if this helps.

Источник

Saving files in Android 11 to external storage(SDK 30)

I am writing a new Application on Android 11 (SDK Version 30) and I simply cannot find an example on how to save a file to the external storage.

I read their documentation and now know that they basicly ignore Manifest Permissions ( READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE ). They also ignore the android:requestLegacyExternalStorage=»true» in the manifest.xml application tag. In their documentation https://developer.android.com/about/versions/11/privacy/storage they write you need to enable the DEFAULT_SCOPED_STORAGE and FORCE_ENABLE_SCOPED_STORAGE flags to enable scoped storage in your app. Where do I have to enable those? And when I’ve done that how and when do I get the actual permission to write to the external storage? Can someone provide working code?
I want to save .gif, .png and .mp3 files. So I don’t want to write to the gallery. Thanks in advance.

Читайте также:  Остановка работы программы питон

5 Answers 5

Corresponding To All Api, included Api 30, Android 11 :

public static File commonDocumentDirPath(String FolderName) < File dir = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) < dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/" + FolderName); >else < dir = new File(Environment.getExternalStorageDirectory() + "/" + FolderName); >// Make sure the path directory exists. if (!dir.exists()) < // Make it, if it doesn't exit boolean success = dir.mkdirs(); if (!success) < dir = null; >> return dir; > 

Now, use this commonDocumentDirPath for saving file.

A side note from comments, getExternalStoragePublicDirectory with certain scopes are now working with Api 30, Android 11. Cheers! Thanks to CommonsWare hints.

dir.mkdirs(); mkdirs() does not throw exceptions but returns true or false. If it returns false you should let your commonDocumentDirPath function return a null. And the caller should check for null.

@BhaveshMoradiya, yes, But now in Android 11 for the above approaches works well for all versions correspondingly. Thanks commonsware hints.

You can save files to the public directories on external storage.

Like Documents, Download, DCIM, Pictures and so on.

In the usual way like before version 10.

what is saf ? and how can the app recognizes the old file that it was created before uninstall, after reinstall ?

As I understand, you actually can use at least 4 directories: DCIM, Download, Movies, and Pictures. Each of them described as «top-level public directory» here: developer.android.google.cn/reference/android/os/…

**Simplest Answer and Tested ( Java ) **

private void createFile(String title) < Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("text/html"); intent.putExtra(Intent.EXTRA_TITLE, title); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) < intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Uri.parse("/Documents")); >createInvoiceActivityResultLauncher.launch(intent); > private void createInvoice(Uri uri) < try < ParcelFileDescriptor pfd = getContentResolver(). openFileDescriptor(uri, "w"); if (pfd != null) < FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor()); fileOutputStream.write(invoice_html.getBytes()); fileOutputStream.close(); pfd.close(); >> catch (IOException e) < e.printStackTrace(); >> ///////////////////////////////////////////////////// // You can do the assignment inside onAttach or onCreate, i.e, before the activity is displayed String invoice_html; ActivityResultLauncher createInvoiceActivityResultLauncher; @Override protected void onCreate(Bundle savedInstanceState) < invoice_html = "

Just for testing received.

"; createInvoiceActivityResultLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> < if (result.getResultCode() == Activity.RESULT_OK) < // There are no request codes Uri uri = null; if (result.getData() != null) < uri = result.getData().getData(); createInvoice(uri); // Perform operations on the document using its URI. >> >);

Using /Documents works but /Downloads not working.. You can also create folder of your choice in Documents folder

I’m using this method and it really worked for me I hope I can help you. Feel free to ask me if something is not clear to you

 Bitmap imageBitmap; OutputStream outputStream ; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) < ContentResolver resolver = context.getContentResolver(); ContentValues contentValues = new ContentValues(); contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME,"Image_"+".jpg"); contentValues.put(MediaStore.MediaColumns.MIME_TYPE,"image/jpeg"); contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH,Environment.DIRECTORY_PICTURES + File.separator+"TestFolder"); Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues); try < outputStream = resolver.openOutputStream(Objects.requireNonNull(imageUri) ); imageBitmap.compress(Bitmap.CompressFormat.JPEG,100,outputStream); Objects.requireNonNull(outputStream); Toast.makeText(context, "Image Saved", Toast.LENGTH_SHORT).show(); >catch (Exception e) < Toast.makeText(context, "Image Not Not Saved: \n "+e, Toast.LENGTH_SHORT).show(); e.printStackTrace(); >> 

manifest file (Add Permission)

Hi @Mark Nashat how to do for android version less than Q. By this I mean how to handle both situation?

by this the code File filePath = Environment.getExternalStorageDirectory(); File dir = new File(filePath.getAbsolutePath() + «/» + context.getString(R.string.app_name) + «/»); dir.mkdir(); File file1 = new File(dir, System.currentTimeMillis() + «.jpg»);

Thank you so much @Mark Nashat. Also, one last thing is how to know if a file exists in external storage in android 10+. Actually, I want to create the file if it does not exist else overwrite it. (Like you suggested answer above)

I know this question is a bit old but here is a working solution to organize your files anywhere except the root phone directory

Читайте также:  Not equals operator in python

First In Your build.gradle file, implement the SAF framework’s DocumentFile class:

implementation 'androidx.documentfile:documentfile:1.0.1' 

Next Call this method which request permissions for the SAF to operate (You will only need to do this once on user install):

 private void requestDocumentTreePermissions() < // Choose a directory using the system's file picker. new AlertDialog.Builder(this) .setMessage("*Please Select A Folder For The App To Organize The Videos*") .setPositiveButton("Ok", new DialogInterface.OnClickListener() < @RequiresApi(api = Build.VERSION_CODES.Q) @Override public void onClick(DialogInterface dialog, int which) < StorageManager sm = (StorageManager) getSystemService(Context.STORAGE_SERVICE); Intent intent = sm.getPrimaryStorageVolume().createOpenDocumentTreeIntent(); String startDir = "Documents"; Uri uri = intent.getParcelableExtra("android.provider.extra.INITIAL_URI"); String scheme = uri.toString(); scheme = scheme.replace("/root/", "/document/"); scheme += "%3A" + startDir; uri = Uri.parse(scheme); Uri rootUri = DocumentsContract.buildDocumentUri( EXTERNAL_STORAGE_PROVIDER_AUTHORITY, uri.toString() ); Uri treeUri = DocumentsContract.buildTreeDocumentUri( EXTERNAL_STORAGE_PROVIDER_AUTHORITY, uri.toString() ); uri = Uri.parse(scheme); Uri treeUri2 = DocumentsContract.buildTreeDocumentUri( EXTERNAL_STORAGE_PROVIDER_AUTHORITY, uri.toString() ); ListuriTreeList = new ArrayList<>(); uriTreeList.add(treeUri); uriTreeList.add(treeUri2); getPrimaryVolume().createOpenDocumentTreeIntent() .putExtra(EXTRA_INITIAL_URI, rootUri); Intent intent2 = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); // Optionally, specify a URI for the directory that should be opened in // the system file picker when it loads. intent2.addFlags( Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION); intent2.putExtra(EXTRA_INITIAL_URI, rootUri); startActivityForResult(intent2, 99); > >) .setCancelable(false) .show(); > 

Next Store some Persistant Permissions:

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) < super.onActivityResult(requestCode, resultCode, data); if (requestCode == 99 && resultCode == RESULT_OK) < //get back the document tree URI (in this case we expect the documents root directory) Uri uri = data.getData(); //now we grant permanent persistant permissions to our contentResolver and we are free to open up sub directory Uris as we please until the app is uninstalled getSharedPreferences().edit().putString(ACCESS_FOLDER, uri.toString()).apply(); final int takeFlags = (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); getApplicationContext().getContentResolver().takePersistableUriPermission(uri, takeFlags); //simply recreate the activity although you could call some function at this point recreate(); >> 

You can call the documentFile’s rename method on the correct file

DocumentFile df = DocumentFile.fromTreeUri(MainActivity.this, uri); df = df.findFile("CurrentName") df.renameTo("NewName"); 

You Can also open InputStreams and OutputStreams using your content resolver because of the persistant URI permissions granted to your content resolver for that DocumentFile using the following snippet:

getContentResolver().openInputStream(df.getUri()); getContentResolver().openOutputStream(df.getUri()); 

InputStreams are for reading and OutputStreams are for saving

Or You can list out files using:

public static DocumentFile findFileInDirectoryMatchingName(Context mContext, Uri mUri, String name) < final ContentResolver resolver = mContext.getContentResolver(); final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(mUri, DocumentsContract.getDocumentId(mUri)); Cursor c = null; try < c = resolver.query(childrenUri, new String[]< DocumentsContract.Document.COLUMN_DOCUMENT_ID, DocumentsContract.Document.COLUMN_DISPLAY_NAME, DocumentsContract.Document.COLUMN_MIME_TYPE, DocumentsContract.Document.COLUMN_LAST_MODIFIED >, DocumentsContract.Document.COLUMN_DISPLAY_NAME + " LIKE '?%'", new String[], null); c.moveToFirst(); while (!c.isAfterLast()) < final String filename = c.getString(1); final String mimeType = c.getString(2); final Long lastModified = c.getLong(3); if (filename.contains(name)) < final String documentId = c.getString(0); final Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(mUri, documentId); return DocumentFile.fromTreeUri(mContext, documentUri); >c.moveToNext(); > > catch (Exception e) < e.printStackTrace(); >finally < if (c != null) < c.close(); >> return null; > 

Which will run faster than the df.listFiles() method

Src (This is my own implementation but here is the original SF question) Renaming Video / Image While Targeting Android 11 (Api 30)

Источник

Android External Storage — Read, Write, Save File

Android External Storage - Read, Write, Save File

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Android external storage can be used to write and save data, read configuration files etc. This article is continuation of the Android Internal Storage tutorial in the series of tutorials on structured data storage in android.

Android External Storage

  • Primary External Storage: In built shared storage which is “accessible by the user by plugging in a USB cable and mounting it as a drive on a host computer”. Example: When we say Nexus 5 32 GB.
  • Secondary External Storage: Removable storage. Example: SD Card

All applications can read and write files placed on the external storage and the user can remove them. We need to check if the SD card is available and if we can write to it. Once we’ve checked that the external storage is available only then we can write to it else the save button would be disabled.

Читайте также:  Php ini memory size limit

Android External Storage Example Project Structure

android external storage

Firstly, we need to make sure that the application has permission to read and write data to the users SD card, so lets open up the AndroidManifest.xml and add the following permissions:

Also, external storage may be tied up by the user having mounted it as a USB storage device. So we need to check if the external storage is available and is not read only.

if (!isExternalStorageAvailable() || isExternalStorageReadOnly()) < saveButton.setEnabled(false); >private static boolean isExternalStorageReadOnly() < String extStorageState = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) < return true; >return false; > private static boolean isExternalStorageAvailable() < String extStorageState = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(extStorageState)) < return true; >return false; > 

getExternalStorageState() is a static method of Environment to determine if external storage is presently available or not. As you can see if the condition is false we’ve disabled the save button.

Android External Storage Example Code

The activity_main.xml layout is defined as follows:

Here apart from the save and read from external storage buttons we display the response of saving/reading to/from an external storage in a textview unlike in the previous tutorial where android toast was displayed. The MainActivity.java class is given below:

package com.journaldev.externalstorage; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import android.os.Bundle; import android.app.Activity; import android.os.Environment; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends Activity < EditText inputText; TextView response; Button saveButton,readButton; private String filename = "SampleFile.txt"; private String filepath = "MyFileStorage"; File myExternalFile; String myData = ""; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); inputText = (EditText) findViewById(R.id.myInputText); response = (TextView) findViewById(R.id.response); saveButton = (Button) findViewById(R.id.saveExternalStorage); saveButton.setOnClickListener(new OnClickListener() < @Override public void onClick(View v) < try < FileOutputStream fos = new FileOutputStream(myExternalFile); fos.write(inputText.getText().toString().getBytes()); fos.close(); >catch (IOException e) < e.printStackTrace(); >inputText.setText(""); response.setText("SampleFile.txt saved to External Storage. "); > >); readButton = (Button) findViewById(R.id.getExternalStorage); readButton.setOnClickListener(new OnClickListener() < @Override public void onClick(View v) < try < FileInputStream fis = new FileInputStream(myExternalFile); DataInputStream in = new DataInputStream(fis); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String strLine; while ((strLine = br.readLine()) != null) < myData = myData + strLine; >in.close(); > catch (IOException e) < e.printStackTrace(); >inputText.setText(myData); response.setText("SampleFile.txt data retrieved from Internal Storage. "); > >); if (!isExternalStorageAvailable() || isExternalStorageReadOnly()) < saveButton.setEnabled(false); >else < myExternalFile = new File(getExternalFilesDir(filepath), filename); >> private static boolean isExternalStorageReadOnly() < String extStorageState = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) < return true; >return false; > private static boolean isExternalStorageAvailable() < String extStorageState = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(extStorageState)) < return true; >return false; > > 
  1. Environment.getExternalStorageState(): returns path to internal SD mount point like “/mnt/sdcard”
  2. getExternalFilesDir(): It returns the path to files folder inside Android/data/data/application_package/ on the SD card. It is used to store any required files for your app (like images downloaded from web or cache files). Once the app is uninstalled, any data stored in this folder is gone too.

android external storage config, android save file to external storage

Also if the external storage is not available we disable the save button using the if condition that was discussed earlier in this tutorial. Below is our application running in android emulator, where we are writing data to file and then reading it. Note: Make sure your Android Emulator is configured such that it has a SD card as shown in the image dialog from AVD below. Go to Tools->Android->Android Virtual Device, edit configurations->Show Advance Settings. This brings an end to this tutorial. We’ll discuss storage using Shared Preferences in the next tutorial. You can download the final Android External Storage Project from the below link.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Источник

Оцените статью