Search code examples
filexamarin.formsdirectoryandroid-external-storage

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

UPDATE

@Lucas Zhang - MSFT I try your dependency service but no file or folder is generating on the device. I can't use PCLStorage since I need to create the file in device external folder.

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


Solution

  • do this in xamarin forms? Or should we need to use a dependency service?

    Option 1:

    Of course we need to use dependency service .

    in Android project

    public async Task SaveAndView(string fileName, String contentType, MemoryStream stream)
            {
                try
                {
                    string root = null;
                    //Get the root path in android device.
                    if (Android.OS.Environment.IsExternalStorageEmulated)
                    {
                        root = Android.OS.Environment.ExternalStorageDirectory.ToString();
                    }
                    else
                        root = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    
                    //Create directory and file 
                    Java.IO.File myDir = new Java.IO.File(root + "/meusarquivos");
                    myDir.Mkdir();
    
                    Java.IO.File file = new Java.IO.File(myDir, fileName);
    
                    //Remove if the file exists
                    if (file.Exists()) file.Delete();
    
                    //Write the stream into the file
                    FileOutputStream outs = new FileOutputStream(file);
                    outs.Write(stream.ToArray());
    
                    outs.Flush();
                    outs.Close();
               }
                catch (Exception ex)
                {
                    //...
                }
            }
    
    await DependencyService.Get<ISave>().SaveAndView(xxx.ToString() + ".pdf", "application/pdf", stream);
    

    Do not forget to add following permission and achieve runtime permission.

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

    in iOS

    iOS imposes some restrictions on what an application can do with the file system to preserve the security of an application’s data, and to protect users from malignant apps. These restrictions are part of the Application Sandbox – a set of rules that limits an application’s access to files, preferences, network resources, hardware, etc. An application is limited to reading and writing files within its home directory (installed location); it cannot access another application’s files.

    You could check the docs for more details .

    Option 2:

    If you do want to implement it in Forms directly . We could use the plugin PCLStorage from nuget .

    Cross-platform Local Folder

    In Xamarin.Form, the PCLStorage API will help us to retrieve all the platforms' local folder names and paths, using the code given below. There is no need to write any platform-specific code to access the local folder.

    Using PCLStorage;  
    
    IFolder folder = FileSystem.Current.LocalStorage; 
    

    Creating new folders

    To create a new subfolder in the local folder, call the CreateFolderAsync method.

    string folderName ="xxx" ;  
    IFolder folder = FileSystem.Current.LocalStorage;  
    folder = await folder.CreateFolderAsync(folderName, CreationCollisionOption.ReplaceExisting);  
    

    Create New file

    To create a new file in the local folder, call the CreateFileAsync method.

    string filename=”username.txt”;  
    IFolder folder = FileSystem.Current.LocalStorage;  
    IFile file = await folder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);  
    

    Check Folder Already Exists

    We can check for an existing folder in a particular folder, as shown below.

    public async static Task<bool> IsFolderExistAsync(this string folderName, IFolder rootFolder = null)  
         {  
             // get hold of the file system  
             IFolder folder = rootFolder ?? FileSystem.Current.LocalStorage;  
             ExistenceCheckResult folderexist = await folder.CheckExistsAsync(folderName);  
             // already run at least once, don't overwrite what's there  
             if (folderexist == ExistenceCheckResult.FolderExists)  
             {  
                 return true;  
      
             }  
             return false;  
         }  
    

    Check File Already Exists

    We can check for an existing file in a particular folder, as shown below.

    public async static Task<bool> IsFileExistAsync(this string fileName, IFolder rootFolder = null)  
            {  
                // get hold of the file system  
                IFolder folder = rootFolder ?? FileSystem.Current.LocalStorage;  
                ExistenceCheckResult folderexist = await folder.CheckExistsAsync(fileName);  
                // already run at least once, don't overwrite what's there  
                if (folderexist == ExistenceCheckResult.FileExists)  
                {  
                    return true;  
      
                }  
                return false;  
            }  
    

    Write File

    If you want to write any extension file document, just use the WriteAllTextAsync method for write.

    public async static Task<bool> WriteTextAllAsync(this string filename, string content = "", IFolder rootFolder = null)  
          {  
              IFile file = await filename.CreateFile(rootFolder);  
              await file.WriteAllTextAsync(content);  
              return true;  
          }  
    

    Note: you still need to add permission in Android project .

    Update

    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://learn.microsoft.com/en-us/xamarin/android/platform/files/external-storage?tabs=windows

    https://learn.microsoft.com/en-us/xamarin/ios/app-fundamentals/file-system#special-considerations