question

SreejithSree-2948 avatar image
0 Votes"
SreejithSree-2948 asked JarvanZhang-MSFT edited

Xamarin forms: How to create folder and a file in device external storage?

I am trying to create a folder and a text file in that folder on the device's external storage. The same as WhatsApp does. Also, I need to write some data to that file.

Is it possible to do this in xamarin forms? Or should we need to use a dependency service?

Thanks in advance

dotnet-xamarin
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

JarvanZhang-MSFT avatar image
1 Vote"
JarvanZhang-MSFT answered JarvanZhang-MSFT edited

I tried this but getting System.UnauthorizedAccessException: 'Access to the path "/storage/emulated/0/Download/myfile.txt" is denied

Hi, @SreejithSree-2948 . Android 10 introduced a new storage paradigm for apps called scoped storage which changes the way apps store and access files on a device's external storage. If you target Android 10 (API level 29) or higher, set the value of android:requestLegacyExternalStorage to true in your app's manifest file.

Check the doc: https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage

I need a create a folder first, then a text file on that folder

You could use File.Exists(xx) to check if the folder exists, and use Directory.CreateDirectory(xx) to create the folder if not. Check the code:

[assembly: Xamarin.Forms.Dependency(typeof(AccessFileImplement))]
namespace TestApplication.Droid
{
    public class AccessFileImplement : IAccessFileService
    {
        void IAccessFileService.CreateFile(string FileName)
        {
            string text = "hello world";
            byte[] data = Encoding.ASCII.GetBytes(text);
            string rootPath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, Android.OS.Environment.DirectoryDownloads);
            var filePathDir = Path.Combine(rootPath, "folder");
            if (!File.Exists(filePathDir))
            {
                Directory.CreateDirectory(filePathDir);
            }
            string filePath = Path.Combine(filePathDir, FileName);
            File.WriteAllBytes(filePath, data);
        }
    }
}

· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

It starts working but has 3 issues.
1. I have added read and write permissions on manifest, but it is not asking at runtime. So that the app is breaking. Any solution?
2. The old text is always replaced by new text. I need the new text as the new line and old text should be there.
3. Currently the folder is creating inside the Downloads folder, is there any way to create the folder in the root folder of the device?
Could you please help me to fix the above issues?

0 Votes 0 ·

I have added read and write permissions on manifest, but it is not asking at runtime. So that the app is breaking. Any solution?

The application may has been granted the permissions, try to test the project on another device to check that.

The old text is always replaced by new text. I need the new text as the new line and old text should be there.

Try using Java.IO.FileOutputStream to write the content to the file.

Java.IO.File file = new Java.IO.File(filePath);
Java.IO.FileOutputStream outputStream = new Java.IO.FileOutputStream(file, true);
outputStream.WriteAsync(data);

Currently the folder is creating inside the Downloads folder, is there any way to create the folder in the root folder of the device?

You could set the root path as tring rootPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath` directly.

string rootPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
0 Votes 0 ·

Here is the complete code about the 'AccessFileImplement' class.

[assembly: Xamarin.Forms.Dependency(typeof(AccessFileImplement))]
namespace TestApplication.Droid
{
    public class AccessFileImplement : IAccessFileService
    {
        void IAccessFileService.CreateFile(string FileName)
        {
            string text = "hello world";
            byte[] data = Encoding.ASCII.GetBytes(text);
            string rootPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
            var filePathDir = Path.Combine(rootPath, "folder");
            if (!File.Exists(filePathDir))
            {
                Directory.CreateDirectory(filePathDir);
            }
            string filePath = Path.Combine(filePathDir, FileName);

            Java.IO.File file = new Java.IO.File(filePath);
            Java.IO.FileOutputStream outputStream = new Java.IO.FileOutputStream(file, true);

            outputStream.WriteAsync(data);
        }
    }
}
0 Votes 0 ·
JarvanZhang-MSFT avatar image
1 Vote"
JarvanZhang-MSFT answered SreejithSree-2948 commented

Hello,​

Welcome to our Microsoft Q&A platform!

I am trying to create a folder and a text file in that folder on the device's external storage ... should we need to use a dependency service?

The File class provides the related method to create, delete, and read files in the shared project, but it can only access the application folder.

File.WriteAllText(fileName, text);
string text = File.ReadAllText(fileName);

To create a file in the external storage, try to achieve the function on the native platform using DependencyService.

//1.create an interface to define the method
public interface IAccessFile
{
    void CreateFile(string FileName);
}

//2.implement the service on the android platform
[assembly: Xamarin.Forms.Dependency(typeof(AccessFileImplement))]
namespace XamarinFirebase.Droid
{
    public class AccessFileImplement : IAccessFile
    {


        void CreateFile(string FileName)
        {
            string text = "xxx";
            byte[] data = Encoding.ASCII.GetBytes(text);
            string DownloadsPath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, Android.OS.Environment.DirectoryDownloads);
            string filePath = Path.Combine(DownloadsPath, FileName);
            File.WriteAllBytes(filePath, data);
        }
    }
}

//3.consume the DependencyService command in the shared project
DependencyService.Get<IAccessFile>().CreateFile("myfile.txt");

It cannot be available on iOS platform, iOS imposes some restrictions on what an application can do with the file system to preserve the security of an application’s data.
An application is limited to reading and writing files within its home directory (installed location); it cannot access another application’s files.

Related tutorials:
https://docs.microsoft.com/en-us/xamarin/android/platform/files/external-storage?tabs=windows
https://docs.microsoft.com/en-us/xamarin/ios/app-fundamentals/file-system#special-considerations


Best Regards,

Jarvan Zhang



If the response is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I tried this but getting System.UnauthorizedAccessException: 'Access to the path "/storage/emulated/0/Download/myfile.txt" is denied.'

This is not actually I am looking for. I need a create a folder first, then a text file on that folder. I need to write data into that file without losing the previous data. That file and folder should be visible on the device file manager because that file is going to use by the users.

I think the interface should have 2 functions.

void CreateFolderAndFile(string folderName,string FileName); //on this function we need to create a folder and file on device folder if it is not already exist. If it already exists do nothing.

void WriteDataToFile(string data); //on this function we need to write the data to the file added on top




0 Votes 0 ·