2

Before we start, I know that many posted similar questions, yet I can't solve my problem.

I try to save a bitmap into the gallery of the Android device, yet I can't manage to get to that specific path.

Here is the code:

string root = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
Java.IO.File myDir = new Java.IO.File(root + "/Screenshots");
myDir.Mkdirs();

string fname = "test_picture.jpg";

Java.IO.File file = new Java.IO.File(myDir, fname);
if (file.Exists())
    file.Delete();
try
{
    FileStream outStream = new FileStream(file.Path, FileMode.OpenOrCreate); //Seems like the problem is here
    finalBitmap.Compress(Bitmap.CompressFormat.Jpeg, 100, outStream);
    outStream.Flush();
    outStream.Close();
}
catch (Exception e)
{
    Toast.MakeText(Activity, e.ToString(), ToastLength.Long).Show();
}

I get this error:

System.IO.DirectoryNotFoundException: Could not find a part of the path "/storage/emulated/0/Screenshots/test_picture.jpg"

What is wrong with the path? What is the origin of the error?

P.S: I have given all the needed permissions.

Daniel Reyhanian
  • 579
  • 4
  • 26
  • Did code create the folder "/Screenshots"? – jdweng Apr 22 '19 at 14:25
  • @jdweng I have no idea where I am supposed to find it since I don't have the permission to enter storage\emulated\0.. Why don't the system just enter the sdCard path? – Daniel Reyhanian Apr 22 '19 at 14:26
  • If you don't have permission to manually go to the folder why do you think you c# code has access to same folder? – jdweng Apr 22 '19 at 14:30
  • @jdweng That's the point. Why can't I get to the sdCard path? – Daniel Reyhanian Apr 22 '19 at 14:34
  • See if following helps. It is using Reading/Writing an XML file on a smart card but the same rules should apply to any file. https://stackoverflow.com/questions/27396592/how-do-i-access-read-from-write-to-documents-folder-in-internal-storage-on-andro – jdweng Apr 22 '19 at 14:45
  • If you are trying to save "externally" from your app and ALSO not within the core system storage, you should be using the SAF to allow the user to choose that location (removable sdcard, usb2go device, 3rd-party file providers, etc...). Review the pickers: https://developer.android.com/guide/topics/providers/document-provider.html (There are plenty of SOs that describe how to test for all the various "physical paths" of items like `sdcard`s, but there is no standard among devices, that is why Google introduced the "Storage Access Framework (SAF)". – SushiHangover Apr 22 '19 at 14:51
  • @SushiHangover Hello, I really don't understand how to do that. I just try to save that bitmap in such a way that the picture will appear in the pictures gallery.. – Daniel Reyhanian Apr 22 '19 at 14:56
  • @DanielReyhanian Totally different question... `var path = GetExternalFilesDir(Android.OS.Environment.DirectoryPictures).AbsoluteFile;` and then preform a media scan for the file to update the media catalog so it shows up in apps like Gallery. – SushiHangover Apr 22 '19 at 15:02
  • @SushiHangover Could you actually write a detailed answer, please? – Daniel Reyhanian Apr 22 '19 at 15:03

1 Answers1

3

I get the next error: System.IO.DirectoryNotFoundException: Could not find a part of the path "/storage/emulated/0/Screenshots/test_picture.jpg".

After testing your code , this error happens in bellow code:

FileStream outStream = new FileStream(file.Path, FileMode.OpenOrCreate);

If using this string root = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath; , you should notice that this is a Public external files .

/storage/emulated/0/Documents

From document ,Android apps must be granted permission before they can read or write any public files. So here you need add permissions in AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

And from android 6.0 , you also need to add runtimer permissions.Here , Suggest that can install Plugin.Permissions NuGet package for project to request a permission.As follow is a example:

OnCreate():

Plugin.CurrentActivity.CrossCurrentActivity.Current.Init(this,savedInstanceState);

Button Click method():

try
{
    var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Storage);
    if (status != PermissionStatus.Granted)
    {
        if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Storage))
        {
            //await DisplayAlert("Need location", "Gunna need that location", "OK");
            Console.WriteLine("OK");
        }

        var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Storage);
        //Best practice to always check that the key exists
        if (results.ContainsKey(Permission.Storage))
            status = results[Permission.Storage];
    }

    if (status == PermissionStatus.Granted)
    {
        string root = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
        Java.IO.File myDir = new Java.IO.File(root + "/Screenshots");
        myDir.Mkdirs();

        string fname = "test_picture.jpg";

        Java.IO.File file = new Java.IO.File(myDir, fname);
        Console.WriteLine("------root-------" + file.Path);

        FileStream outStream = new FileStream(file.Path, FileMode.OpenOrCreate);
        ....
    }
    else if (status != PermissionStatus.Unknown)
    {
        Console.WriteLine("OK");
        //await DisplayAlert("Location Denied", "Can not continue, try again.", "OK");
    }
}
catch (Exception ex)
{
    Console.WriteLine("" + ex);
}

Other solution:

If not using Public external files , you can have a try with Private external files

/storage/emulated/0/Android/data/com.companyname.app/files/

This do not need to require a runtime permission.However static permission in AndroidManifest.xml is also needed.

string root = Application.Context.GetExternalFilesDir("DirectoryPictures").ToString();
Junior Jiang
  • 12,430
  • 1
  • 10
  • 30