How to Get File Path from URI in Android Oreo (8.1) or above
Asked Answered
D

5

10

Expected Behavior

When I am selecting the file which is stored inside "Download", it should able to retrieves its file name and path

Actual Behavior

When I am selecting the file which is stored inside "Download", it returns null.

Steps to Reproduce the Problem

  1. When picking file method is called, it displays the folders in Android
  2. Go to downloads, select a file
  3. It returns null in getting real path from URI

Here is the code what i implemented

public static String getPath(final Context context, final Uri uri) {
   String id = DocumentsContract.getDocumentId(uri);
   if (!TextUtils.isEmpty(id)) {
      if (id.startsWith("raw:")) {
          return id.replaceFirst("raw:", "");
      }
      try {
         final boolean isOreo = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
         String stringContentURI;
         Uri contentUri;
         if(isOreo){ 
            stringContentURI = "content://downloads/my_downloads";
         }else{
            stringContentURI = "content://downloads/public_downloads";
         }
         contentUri = ContentUris.withAppendedId(
                    Uri.parse(stringContentURI), Long.valueOf(id));
         return getDataColumn(context, contentUri, null, null);
      } catch (NumberFormatException e) {
         return null;
      }
   }
}

public static String getDataColumn(Context context, Uri uri, String selection,
                                   String[] selectionArgs) {
    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {   column};
    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                null);
        if (cursor != null && cursor.moveToFirst()) {
            final int index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}

However, it is working when selecting file from other folders in Android device

Please advise. Thanks everyone :)

Decastere answered 12/10, 2018 at 8:30 Comment(0)
D
23

For now, the best approach for getting path is :

Getting physical file from URI as InputStream, ContentResolver.openInputStream() allow you to access the contents of a file without knowing its real path

String id = DocumentsContract.getDocumentId(uri);
InputStream inputStream = getContentResolver().openInputStream(uri);

then write it as a temporary file in cached storage

File file = new File(getCacheDir().getAbsolutePath()+"/"+id);
writeFile(inputStream, file);
String filePath = file.getAbsolutePath();

Here is the method to write temporary file into cached storage

void writeFile(InputStream in, File file) {
     OutputStream out = null;
     try {
          out = new FileOutputStream(file);
          byte[] buf = new byte[1024];
          int len;
          while((len=in.read(buf))>0){
            out.write(buf,0,len);
          }
     } catch (Exception e) {
          e.printStackTrace();
     }
     finally {
          try {
            if ( out != null ) {
                 out.close();
            }
            in.close();
          } catch ( IOException e ) {
               e.printStackTrace();
          }
     }
}

Not sure if its the best way to do, but the code is working properly :D

Decastere answered 15/10, 2018 at 10:4 Comment(4)
But it still doesn't give you the real file path.Mach
This is a life-saving solution. Thanks. But am still wondering why the google guys can't keep it simple. I think this is a lot of work just to get a file path.Hygrophilous
@Decastere just left an answer, which is less complex - and it returns the actual path.Petiolate
@Decastere Its working fine till Android N, but in Android P it's not working when picking images from Downloads folder, and crashing. Can you suggest any other way for the same.Gerhard
E
4

this is activity instance variable

*************************************************************************
*************************************************************************  

    Uri filePath;
    String strAttachmentFileName = "",//attached file name
            strAttachmentCoded = "";//attached file in byte code Base64
    int PICK_REQUEST =1;
*************************************************************************
*************************************************************************  

this is in activity method

*************************************************************************
*************************************************************************  

Button buttonChoose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setType("file/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(Intent.createChooser(intent, "Select any file"), PICK_REQUEST );
            }
        });
*************************************************************************
*************************************************************************  

this is overrride activity method

*************************************************************************
*************************************************************************



    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PICK_REQUEST && resultCode == Activity.RESULT_OK && data != null && data.getData() != null) {
            filePath = data.getData();
            File uploadFile = new File(FileUtils.getRealPath(activity.this, filePath));
            try {
                if (uploadFile != null) {
                    strAttachmentFileName = uploadFile.getName();
                    FileInputStream objFileIS = new FileInputStream(uploadFile);
                    ByteArrayOutputStream objByteArrayOS = new ByteArrayOutputStream();
                    byte[] byteBufferString = new byte[1024];
                    int readNum;
                    readNum = objFileIS.read(byteBufferString);
                    while (readNum != -1) {
                        objByteArrayOS.write(byteBufferString, 0, readNum);
                        readNum = objFileIS.read(byteBufferString);
                    }
                    strAttachmentCoded  = Base64.encodeToString(objByteArrayOS.toByteArray(), Base64.DEFAULT);

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

*************************************************************************
*************************************************************************  

Please create file FileUtils.java as below

link HBiSoft



For Any Type of File in .Net ---
byte[] p = Convert.FromBase64String("byte string");

MemoryStream ms = new MemoryStream(p);
FileStream fs = new FileStream
        (System.Web.Hosting.HostingEnvironment.MapPath("~/ComplaintDetailsFile/") +
                item.FileName, FileMode.Create);
ms.WriteTo(fs);
ms.Close();
fs.Close();
fs.Dispose();
Emeldaemelen answered 17/7, 2019 at 5:55 Comment(1)
perfect solutionPensionary
E
2

Here is another solution that I found from this gist. FileUtils.java

Here is how to use it.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Uri uri = data.getData();
    File originalFile = new File(FileUtils.getRealPath(this,uri));
}
Esteban answered 9/4, 2019 at 12:47 Comment(1)
i dont know why give 'answer not full' for this answer, but this is usefull for me, thanks @nimrod-maniaAlfie
A
1

Below API will be useful.We need to create file in our app's cache and return the same path because of restrictions i.e Scoped storage.

fun createFileAndGetPathFromCacheFolder(context: Context, uri: Uri): String? {
    var inputStream: FileInputStream? = null
    var outputStream: FileOutputStream? = null
    try {
        val parcelFileDescriptor = context.contentResolver.openFileDescriptor(uri, "r", null)
        inputStream = FileInputStream(parcelFileDescriptor?.fileDescriptor)
        val file = File(context.cacheDir, context.contentResolver.getFileName(uri))
        outputStream = FileOutputStream(file)
        val buffer = ByteArray(1024)
        var len: Int
        while (inputStream.read(buffer).also { len = it } != -1) {
            outputStream.write(buffer, 0, len)
        }
        return file.absolutePath
    } catch (e: Exception) {

    } finally {
        inputStream?.close()
        outputStream?.close()
    }
    return " "
}
Aldous answered 28/1, 2021 at 12:0 Comment(0)
P
0

This is what I've just came up with (it's tested on Android Pie & is assuming a SD Card):

private String getParentDirectory(@NonNull Uri uri) {
    String uriPath = uri.getPath();
    String filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
    if(uriPath != null) {filePath = new File(filePath.concat("/" + uriPath.split(":")[1])).getParent();}
    return filePath;
}

private String getAbsolutePath(@NonNull Uri uri) {
    String uriPath = uri.getPath();
    String filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
    if(uriPath != null) {filePath = filePath.concat("/" + uriPath.split(":")[1]);}
    return filePath;
}
Petiolate answered 11/4, 2019 at 17:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.