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); – CyBer2t Oct 30 '12 at 06:19
10 Answers
Use this method, it works
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();
}
}
}

- 11,307
- 33
- 124
- 222

- 559
- 3
- 3
-
4on the Android 5.x (Lollipop), must include: - Create empty file for ‘destinationFilename’ before using FileOutputStream to avoid throw IOException! – hungtdo May 19 '15 at 08:28
-
1This 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. – Eugen Pechanec Sep 25 '19 at 06:54
-
Use ContentResolver: Change sourceuri.getPath() with this: https://stackoverflow.com/a/13275282/8283938 – Falke Design Oct 06 '19 at 10:36
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[]{DocumentsContract.Document.COLUMN_FLAGS},
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;
}
Overall, you can use
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.

- 1,268
- 18
- 22
private static String FILE_NAM = "video";
String outputfile = getFilesDir() + File.separator+FILE_NAM+"_tmp.mp4";
InputStream in = getContentResolver().openInputStream(videoFileUri);
private static File createFileFromInputStream(InputStream inputStream, String fileName) {
try {
File f = new File(fileName);
f.setWritable(true, false);
OutputStream outputStream = new FileOutputStream(f);
byte buffer[] = new byte[1024];
int length = 0;
while((length=inputStream.read(buffer)) > 0) {
outputStream.write(buffer,0,length);
}
outputStream.close();
inputStream.close();
return f;
} catch (IOException e) {
System.out.println("error in creating a file");
e.printStackTrace();
}
return null;
}

- 166
- 3
- 14

- 147
- 1
- 3
-
-
@Azurespot InputStream and OutputStream use a byte buffer to read and write. In inputStrea.read(buffer), the method takes the buffer array and fills it. The OutputStream, set to the appropriate filename, takes the buffer array and writes its contents. However, I found a very neat solution to take an input stream and convert it to a String instead. Put this in some sort of Util class and you are good to go. Take a look here: https://stackoverflow.com/a/5445161/4687402 – Benjamin Basmaci Mar 01 '19 at 16:06
I have used following code to save a file from an existing Uri given back from an Intent to an Uri that my App hosts:
private void copyFile(Uri pathFrom, Uri pathTo) throws IOException {
try (InputStream in = getContentResolver().openInputStream(pathFrom)) {
if(in == null) return;
try (OutputStream out = getContentResolver().openOutputStream(pathTo)) {
if(out == null) return;
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
}
}

- 133
- 1
- 9
-
1... as there are already posted 7 answer that look similar... please do explain in your answer why yours is beneficial over others (itherwise it belomes a low-quality answer and might be deleted at all). (From Review). – ZF007 Dec 18 '19 at 15:56
-
4The other answers goes from an Uri to a file, in my answer it shows how to save a file from one Uri to another Uri. – Sebi Dec 19 '19 at 08:02
Here's the easiest and the cleanest:
private void saveFile(Uri sourceUri, File destination)
try {
File source = new File(sourceUri.getPath());
FileChannel src = new FileInputStream(source).getChannel();
FileChannel dst = new FileOutputStream(destination).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}

- 11,199
- 1
- 48
- 63
-
Hi, would `destination` be the entire `File` path including name of file? Or just the directory name/path? – Azurespot Mar 30 '15 at 02:22
-
1Destination is type of `File` denoting the entire file with its name. – Ε Г И І И О Apr 09 '15 at 05:13
-
2Using this code I get `java.io.FileNotFoundException: /document/image:18019: open failed: ENOENT (No such file or directory)` – Filip Hazubski Sep 14 '15 at 16:58
-
-
7@ΕГИІИО It speaks that your code does not work with `URI` returned by the `Intent` opening gallery for choosing an image. At least it did not worked for me and probably someone who voted up my comment. I tested it with Android 5.1.1. – Filip Hazubski Dec 10 '15 at 09:41
-
I don't think content uri's return an absolute path. Which is why this answer does not work with some Uris. – lostintranslation Aug 31 '16 at 16:23
-
It's obviously wrong solution. Don't try to get path, content uri will not return direct file path. Use InputStream instead. – user1209216 Aug 23 '17 at 21:36
When receiving a android.net.Uri
from an external source, the best way to save the file is from the stream:
try (InputStream ins = activity.getContentResolver().openInputStream(source_uri)) {
File dest = new File(destination_path);
createFileFromStream(ins, dest);
} catch (Exception ex) {
Log.e("Save File", ex.getMessage());
ex.printStackTrace();
}
createFileFromStream
method:
public static void createFileFromStream(InputStream ins, File destination) {
try (OutputStream os = new FileOutputStream(destination)) {
byte[] buffer = new byte[4096];
int length;
while ((length = ins.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
os.flush();
} catch (Exception ex) {
Log.e("Save File", ex.getMessage());
ex.printStackTrace();
}
}

- 8,397
- 4
- 64
- 80
1.Create a file from a URI path as:
File from = new File(uri.toString());
2.Create another File where you want the file to save as:
File to = new File("target file path");
3.Rename the file as:
from.renameTo(to);
With this the file from default path is automatically deleted and created at the new path.

- 719
- 3
- 6
-
Gurmeet, If i have to retain the existing file also, then how to proceed? I need to create a new file or a duplicate copy. – CyBer2t Oct 30 '12 at 06:26
-
@CyBer2t Then you need a file copy.Here is the stackoverflow [internal link](http://stackoverflow.com/questions/4615693/android-file-copy) showing file copy. – AppMobiGurmeet Oct 30 '12 at 06:30
-
1uri.toString and uri.toPath() don't always work, especially with the gallery. I suspect using inputstreams is the way to go. – ssimm Feb 03 '16 at 15:09
How to get external storage location and save a file
This answer is not for the question, but for the title. It took hours to figure out how to do this since no article explains the process totally, while some of them are years old and uses deprecated APIs. Hope this might be helpful for future developers.
Get location of External Storage
For instance, from inside a fragment,
// when user choose file location
private val uriResult = registerForActivityResult(ActivityResultContracts.CreateDocument()) { uri ->
// do when user choose file location
createFile(uri)
}
fun openFileChooser() {
// startActivityForResult() is deprecated
val suggestedFileName = "New Document.txt"
uriResult.launch(suggestedFileName)
}
Write file data using Uri
It may seem difficult to create a java.io.File
from an android.net.Uri
, since there is no direct way to convert an android.net.Uri
into java.net.URI
. But if you have the ApplicationContext
you can do it very easily.
fun createFile(uri: Uri) {
try {
requireContext().applicationContext.contentResolver.openFileDescriptor(uri, "w")?.use { fd ->
FileOutputStream(fd).use { fos ->
// do your job on the FileOutputStream
// also use background thread
fos.close()
}
}
} catch (e: Exception) {
}
}
Note: File operations throws multiple exceptions, so handle them carefully. And also do file operations in worker threads.

- 772
- 1
- 6
- 18
-
For anyone who has problems with this topic: I had to use ```openOutputStream(destination)``` instead of ```openFileDescriptor(uri, "w")``` – Matei Macoveiciuc May 04 '22 at 18:23
I slightly modified Sebi's answer to work for Kotlin:
fun copyUri(context: Context, pathFrom: Uri, pathTo: Uri?) {
context.contentResolver.openInputStream(pathFrom).use { inputStream: InputStream? ->
if (pathTo == null || inputStream == null) return
context.contentResolver.openOutputStream(pathTo).use { out ->
if (out == null) return
// Transfer bytes from in to out
val buf = ByteArray(1024)
var len: Int
while (inputStream.read(buf).also { len = it } > 0) {
out.write(buf, 0, len)
}
}
}
}

- 2,953
- 4
- 29
- 39
You can do it using
new File(uri.getPath());

- 495
- 4
- 5
-
The uri.getPath() can resolve to something that is not a valid file path. – Iogui Feb 09 '21 at 23:38