0

I have just saved a file using the path created by:

string documentsPath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, Android.OS.Environment.DirectoryDocuments);
fileName = System.IO.Path.Combine(documentsPath, fileData.FileName);

The file path ends up being and is saved successfully: /storage/emulated/0/Documents/test.csv

I now use the file picker to select the file as such:

 FileData fileData = await CrossFilePicker.Current.PickFile();   

but the returned fileData.FilePath is: content://com.android.externalstorage.documents/document/home%3Atest.csv

This path then doesn't work sticking it into a:

 StreamReader sr = new StreamReader (fileData.FilePath);

However, if I use that path from .DirectoryDocuments above with the filename, StreamReader opens it just fine.

So, @vividos, how can that file picker path be translated into the real path StreamReader can use?

karhukoti
  • 1
  • 3

2 Answers2

1

You should use the Xamarin.Android-based overload on Stream that can open a content://-based uri as the modern Android API-levels will prevent you from directly obtaining a file://-based uri due to security concerns:

System.IO.Stream.OpenInputStream (Android.Net.Uri uri);

This overload is translated from the Android.Content.Contentresolver.Openinputstream.

re: https://learn.microsoft.com/en-us/dotnet/api/android.content.contentresolver.openinputstream?view=xamarin-android-sdk-9

SushiHangover
  • 73,120
  • 10
  • 106
  • 165
  • I get: Stream does not contain a definition for 'OpenInputStream'. @sushihangover Is there something in particular I need to do? – karhukoti Oct 31 '19 at 11:29
0

how can that file picker path be translated into the real path StreamReader can use?

I use your code to test, but I don't get content:// uri from fileData.FilePath, but if you want to translate file picker path to real path, I suggest you can use the following code to try.

 private string GetActualPathFromFile(Android.Net.Uri uri)
    {
        bool isKitKat = Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat;

        if (isKitKat && DocumentsContract.IsDocumentUri(this, uri))
        {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri))
            {
                string docId = DocumentsContract.GetDocumentId(uri);

                char[] chars = { ':' };
                string[] split = docId.Split(chars);
                string type = split[0];

                if ("primary".Equals(type, StringComparison.OrdinalIgnoreCase))
                {
                    return Android.OS.Environment.ExternalStorageDirectory + "/" + split[1];
                }
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri))
            {
                string id = DocumentsContract.GetDocumentId(uri);

                Android.Net.Uri contentUri = ContentUris.WithAppendedId(
                                Android.Net.Uri.Parse("content://downloads/public_downloads"), long.Parse(id));

                //System.Diagnostics.Debug.WriteLine(contentUri.ToString());

                return getDataColumn(this, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri))
            {
                String docId = DocumentsContract.GetDocumentId(uri);

                char[] chars = { ':' };
                String[] split = docId.Split(chars);

                String type = split[0];

                Android.Net.Uri contentUri = null;
                if ("image".Equals(type))
                {
                    contentUri = MediaStore.Images.Media.ExternalContentUri;
                }
                else if ("video".Equals(type))
                {
                    contentUri = MediaStore.Video.Media.ExternalContentUri;
                }
                else if ("audio".Equals(type))
                {
                    contentUri = MediaStore.Audio.Media.ExternalContentUri;
                }

                String selection = "_id=?";
                String[] selectionArgs = new String[]
                {
            split[1]
                };

                return getDataColumn(this, contentUri, selection, selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
        {

            // Return the remote address
            if (isGooglePhotosUri(uri))
                return uri.LastPathSegment;

            return getDataColumn(this, uri, null, null);
        }
        // File
        else if ("file".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
        {
            return uri.Path;
        }

        return null;
    }

    public static String getDataColumn(Context context, Android.Net.Uri uri, String selection, String[] selectionArgs)
    {
        ICursor cursor = null;
        String column = "_data";
        String[] projection =
        {
    column
};

        try
        {
            cursor = context.ContentResolver.Query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.MoveToFirst())
            {
                int index = cursor.GetColumnIndexOrThrow(column);
                return cursor.GetString(index);
            }
        }
        finally
        {
            if (cursor != null)
                cursor.Close();
        }
        return null;
    }

    //Whether the Uri authority is ExternalStorageProvider.
    public static bool isExternalStorageDocument(Android.Net.Uri uri)
    {
        return "com.android.externalstorage.documents".Equals(uri.Authority);
    }

    //Whether the Uri authority is DownloadsProvider.
    public static bool isDownloadsDocument(Android.Net.Uri uri)
    {
        return "com.android.providers.downloads.documents".Equals(uri.Authority);
    }

    //Whether the Uri authority is MediaProvider.
    public static bool isMediaDocument(Android.Net.Uri uri)
    {
        return "com.android.providers.media.documents".Equals(uri.Authority);
    }

    //Whether the Uri authority is Google Photos.
    public static bool isGooglePhotosUri(Android.Net.Uri uri)
    {
        return "com.google.android.apps.photos.content".Equals(uri.Authority);
    }

More detailed info, you can take a look:

How to get actual path from Uri xamarin android

Cherry Bu - MSFT
  • 10,160
  • 1
  • 10
  • 16
  • Cherry, what kind of path did you get? – karhukoti Oct 31 '19 at 11:30
  • @karhukoti, I try your code, but I don't get content:// uri from fileData.FilePath, I just get actual path, so I have no change to try, you can add this method to try, and see if it will return the path that you want. – Cherry Bu - MSFT Nov 01 '19 at 01:06