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
do this in xamarin forms? Or should we need to use a dependency service?
Of course we need to use dependency service .
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" />
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 .
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 .
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