-1

I am using FilePicker-Plugin-for-Xamarin-and-Windows and got this error while accessing external storage:

Could not find a part of the path "/content:/com.android.externalstorage.documents/document/6759-130B%3ANew%20Text%20Document.txt".

enter image description here

Note:I have both read and write permissions And also I ask user at runtime.
When using this path problem gone:

storage/6759-130B%3ANew%20Text%20Document.txt

This is very known old bug in picker as officially mentioned.

For me it looks like I have to convert content:// into file path.

More info

Sorry IwontTell
  • 466
  • 10
  • 29
  • HI, i had the same issue awhile ago, i dont remember it much, but i guess the issue was with the URI you getting & passing it over. when content comes, its different than the original path, you have to handle it accorddingly – Blu Sep 12 '20 at 14:38
  • The plugin is good, it has no issues. Theres some kind of handling to get over it. – Blu Sep 12 '20 at 14:41
  • [Plugin owner officially mentions this bug](https://github.com/jfversluis/FilePicker-Plugin-for-Xamarin-and-Windows#important). – Sorry IwontTell Sep 12 '20 at 15:47

1 Answers1

1

I remembered the thing, You need to get the absolute path from your uri. Usually, content:// path is returned from download folder or any drive path, you need to get actual path for it. You can try this.

Its an device specific code for Android, Inject it with dependency service.

I faced above issue in Native android & solved that as follows in Java, below is the converted code for the same in c#

private string GetRealPathFromURI(Uri contentURI)
{
    ICursor cursor = ContentResolver.Query(contentURI, null, null, null, null);
    cursor.MoveToFirst();
    string documentId = cursor.GetString(0);
    documentId = documentId.Split(':')[1];
    cursor.Close();

    cursor = ContentResolver.Query(
    Android.Provider.MediaStore.Images.Media.ExternalContentUri,
    null, MediaStore.Images.Media.InterfaceConsts.Id + " = ? ", new [] { documentId }, null);
    cursor.MoveToFirst();
    string path = cursor.GetString(cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.Data));
    cursor.Close();

    return path;
}

EDIT -

Try this

       FileData fileData = await CrossFilePicker.Current.PickFile();
       string filePath;
       if (fileData != null)
       {
            await Task.Run(() => {
            filePath = DependencyService.Get<IImageUtilities>().SaveFileFromStream(new MemoryStream(fileData.DataArray), fileData.FileName));
        });

Code for Xamarin.Android

public string SaveFileFromStream((System.IO.Stream imageStream,  string filename)
{
            string name = filename;
            string filePath = null;
            try
            {
                byte[] imageData = ((MemoryStream)imageStream).ToArray();
                IFolder folder = FileSystem.Current.GetFolderFromPathAsync(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures).ToString()).Result;
                IFile file = folder.CreateFileAsync(name, CreationCollisionOption.GenerateUniqueName).Result;
                filePath = System.IO.Path.Combine(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures).ToString(), file.Name);

                System.IO.Stream outputStream = file.OpenAsync(PCLStorage.FileAccess.ReadAndWrite).Result;
                outputStream.Write(imageData, 0, imageData.Length);
                outputStream.Flush();
                outputStream.Close();
            }
            catch(Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            return filePath;
}

Later on, the new path of the file is used everywhere needed accordingly.

This is what I actually do in my project, whichever file is selected by the user, it is copied to Pictures Dir in internal storage & returns the path.

We deal with the ImageStream to make a copy of the original document. The idea to make a duplicate copy is that we uses the copy for uploading purpose as the user may delete the original document selected. So after pushing the document to the server, we delete the copied file as well. So as we deal with the stream we don't face any issue with Content://.

Hope this maybe helpful.

Blu
  • 821
  • 4
  • 17
  • 1
    wait me i try it – Sorry IwontTell Sep 12 '20 at 15:47
  • I have some problems in ambitious imports. Does this answer is for (Xamarin.Forms.Android) or (Xamarin.Android) ? Because both have different mechanism.Could you also put your imports as well please ? – Sorry IwontTell Sep 13 '20 at 09:19
  • I manage it to work. But it not working. It giving me null string and thats why throws error object no set to instance of object or something like. – Sorry IwontTell Sep 13 '20 at 18:16
  • 1
    @SorryIwontTell check this one. It's something different but it may be helpful. :) – Blu Sep 14 '20 at 11:21
  • Did you tested it ? I guess it will hang while handling big files like 1 gb or more. Instead copying to pictures I guess It should be put in temp folders. – Sorry IwontTell Sep 14 '20 at 11:48
  • 1
    we have tested it for size upto 500mb, not more than that. In some cases it even has issues if there's no enough space for the duplication of the large files. But that's not case for us, we already limit size for selection upto 80mb, no file is selected above it. – Blu Sep 14 '20 at 13:14
  • limit size in file picker ? may be because all bytes loading at once isn't good idea. – Sorry IwontTell Sep 15 '20 at 15:13
  • actually limit size is due to the server-side, we got a limitation by the server that user can upload a file of maximum size of 80mb, but he can select multiple files of 80 mb & less – Blu Sep 15 '20 at 15:22
  • ending up this journey as I already verified from [maintainer](https://github.com/jfversluis/FilePicker-Plugin-for-Xamarin-and-Windows/issues/204#issuecomment-692880628) – Sorry IwontTell Sep 19 '20 at 17:47