10

1)Target set to Android Q with android.permission.WRITE_EXTERNAL_STORAGE

2) use getExternalStorageDirectoryor getExternalStoragePublicDirectoryand FileOutputStream(file)saving file throws

java.io.FileNotFoundException: /storage/emulated/0/myfolder/mytext.txt open failed: ENOENT (No such file or directory)

3) use getExternalFilesDirapi and saving is success but wont show up even after MediaScannerConnection.scanFile.

     /storage/emulated/0/Android/data/my.com.ui/files/Download/myfolder/mytext.txt

What is best way to copy file from internal memory to SDCARD in android Q and refresh.

Noaman Akram
  • 3,680
  • 4
  • 20
  • 37
NitZRobotKoder
  • 1,046
  • 8
  • 44
  • 74

6 Answers6

15

In Android API 29 and above you can use the below code to store files, images and videos to external storage.

//First, if your picking your file using "android.media.action.IMAGE_CAPTURE" then store that file in applications private Path(getExternalFilesDir()) as below.

File destination = new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName);

//Then use content provider to get access to Media-store as below.

 ContentValues values = new ContentValues(); 
 values.put(MediaStore.Images.Media.TITLE, fileName); 
 values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);

//if you want specific mime type, specify your mime type here. otherwise leave it blank, it will take default file mime type

values.put(MediaStore.Images.Media.MIME_TYPE, "MimeType"); 
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000); 
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()); 
values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/" + "path"); // specify 
 storage path

// insert to media-store using content provider, it will return URI.

Uri uri = cxt.getContentResolver().insert(MediaStore.Files.getContentUri("external"), values); 

//Use that URI to open the file.

ParcelFileDescriptor descriptor = context.getContentResolver().openFileDescriptor(uri,"w"); //"w" specify's write mode
FileDescriptor fileDescriptor = descriptor.getFileDescriptor();

// read file from private path.

InputStream dataInputStream = cxt.openFileInput(privatePath_file_path);

//write file into out file-stream.

 OutputStream output = new FileOutputStream(fileDescriptor);
 byte[] buf = new byte[1024];
 int bytesRead;
 while ((bytesRead = dataInputStream.read(buf)) > 0) 
 {
  output.write(buf, 0, bytesRead);
 }
 datanputStream.close();
 output.close();
}
Shiva
  • 207
  • 2
  • 7
  • 1
    how to check file is exists or not. – sk panchal Jan 23 '20 at 02:51
  • 2
    what is the private file path ? – cahix Apr 13 '20 at 21:20
  • 1
    where is destination used? – abat Apr 19 '20 at 08:02
  • 1
    Not working for me. Tried to set `privatePath_file_path` as path and it throws an exception because the parameter contains path separators: tried to put fileName only and it fails because it looks for `/data/my.app.package/files/myFile` (while it should look for `/storage/emulated/0/Android/data/my.app.package/files/myfile` ) – ocramot May 02 '20 at 15:06
  • Private path: data/user/0/com.mypakage.ui/files – Shiva May 04 '20 at 11:18
  • @ocramot from Android OS Q onwards, there is no permission to access /storage/emulated/0/ path, you need to store your files in this /data/my.app.package/files/myFile path only. – Shiva May 04 '20 at 11:20
  • Can you help me with https://stackoverflow.com/questions/63543414/rename-file-of-the-external-storage-which-is-created-by-app-in-android-10-worki – jazzbpn Aug 24 '20 at 03:46
13

In Android Q direct File access is disabled by default for the apps outside their private folders. Here few strategies you can use:

  1. Use the manifest option requestLegacyStorage to have the old behavior but it won't work anymore with Android R, so it's really a short term solution;
  2. Save your files using getExternalFilesDir() method. It's your private folder, other apps could access these files only if they have READ_EXTERNAL_STORAGE permission. In this case it would be good to use FileProvider to grant access to other apps to your files.
  3. Use MediaStore API to insert your media directly. This approach is good for videos, music and photos.
  4. Use the method getPrimaryStorageVolume().createOpenDocumentTreeIntent() of class StorageManager to ask for access to the extenal primary volume. In this case you need user consent and you won't be able to use File api directly anyway, but using DocumentFile class you have a very similar interface, so this is the solution closer to the old behavior. It works if you need to perform operations in foreground and background, i.e. without user interaction with the exception the first interaction to request the permission.
  5. Use ACTION_CREATE_DOCUMENT to create a file using SAF. This option is valid if you do this operation in foreground because you will need the folder selection by the user.

I link Flipper library for point 4, it helps to manage files like in older android versions.

greywolf82
  • 21,813
  • 18
  • 54
  • 108
  • https://developer.android.com/guide/topics/providers/document-provider#create Able to make it work using this. – NitZRobotKoder Aug 06 '19 at 08:31
  • is there option to create folder of my name and copy there in SDCARD via Document-provider? – NitZRobotKoder Aug 06 '19 at 08:40
  • Not directly, but you can ask SdCard access using option 4 using the removable no primary storage returned by method getStorageVolumes – greywolf82 Aug 06 '19 at 08:42
  • @greywolf82 can you please explain more this point : **3 - Use MediaStore API to insert your media directly. This approach is good for videos, music and photos.** – Mouaad Abdelghafour AITALI Sep 14 '19 at 13:02
  • you ask the system to create a new entry, in this way you don't need to ask for a media rescan and you don't need to manage "files". Take a look a MediaStoreCompat of Flipper library. – greywolf82 Sep 14 '19 at 13:06
  • 1
    @greywolf82 I think I had the same issue with File API in android 10 beta builds. I've fixed it with Storage access framework. But in android Q official release build, `FileOutputStream(file)` is no longer throwing this exception. I am not using `requestLegacyStorage = true` and my tagetsdk and compileSdk are 29. Did google change anything in final release? – Aswin P Ashok Nov 12 '19 at 13:39
4

Add android:requestLegacyExternalStorage="true" in <application> tag in Android Manifest, which will allow you to use All File APIs, for now.

Darshan
  • 4,020
  • 2
  • 18
  • 49
  • Yes that works.. Want to make it work without that option. – NitZRobotKoder Aug 06 '19 at 07:26
  • 1
    @NitZRobotKoderThere's no other way than using SAF. – Darshan Aug 06 '19 at 07:28
  • 1
    You mean this way ?https://developer.android.com/guide/topics/providers/document-provider#create – NitZRobotKoder Aug 06 '19 at 07:49
  • 2
    "no other way": you can also drop support from Android R+ onward and ignore the platform completely. There's always some option... :) (I didn't downvote, but it would be nice to mention this flag is only temporary for Android Q, but the other answer is a bit more complete any way ... although it could have mentioned SAF more explicitly (I'm just eating my popcorn here)) – Ped7g Aug 06 '19 at 08:24
  • android:requestLegacyExternalStorage="true" – mio Feb 06 '20 at 11:20
4

Temporary possibility: you can use android:requestLegacyExternalStorage="true" in <application> tag in Android Manifest.

t0m
  • 3,004
  • 31
  • 53
  • 1
    What is the difference between your answer and https://stackoverflow.com/a/57370857/5550161 – HB. Mar 08 '20 at 14:34
1

1)Use Document-provider https://developer.android.com/guide/topics/providers/document-provider#create

2)User will be asked to save(total number of files) and get stored in documents folder. https://gist.github.com/neonankiti/05922cf0a44108a2e2732671ed9ef386

NitZRobotKoder
  • 1,046
  • 8
  • 44
  • 74
1

If you use preserveLegacyExternalStorage, the legacy storage model remains in effect only until the user uninstalls your app. If the user installs or reinstalls your app on a device that runs Android 11, then your app cannot opt out the scoped storage model, regardless of the value of preserveLegacyExternalStorage.

Something to remember when using this flag. know more