ryosu
ryosu

Reputation: 327

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

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 :)

Upvotes: 10

Views: 10895

Answers (5)

Tarun Anchala
Tarun Anchala

Reputation: 2702

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 " "
}

Upvotes: 1

Martin Zeitler
Martin Zeitler

Reputation: 76569

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;
}

Upvotes: 0

pruthwiraj.kadam
pruthwiraj.kadam

Reputation: 1093

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();

Upvotes: 4

NIMROD MAINA
NIMROD MAINA

Reputation: 332

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));
}

Upvotes: 2

ryosu
ryosu

Reputation: 327

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

Upvotes: 23

Related Questions