In our production app we rarely get this exception which causes our app to crash: System.IO.IOException: The file '/sdcard' already exists
The app is a Xamarin.Forms app written in C# and runs on thousands of our own devices with Android 8.1 and 10. At every app start in the constructor of the App class we create a connection to an SQLite database. The database file is stored on the external storage under /sdcard/mycompany/somesubfolder. The devices don't use real SD-cards as storage though but the built-in storage.
Here is the method where the exception is thrown.
protected SQLiteAsyncConnection CreateDatabaseConnection(string databaseFilePath)
{
if (string.IsNullOrWhiteSpace(databaseFilePath))
throw new ArgumentOutOfRangeException(nameof(databaseFilePath), "Argument cannot be null, empty or whitespace!");
var directory = Path.GetDirectoryName(databaseFilePath);
try
{
if (directory != null && !Directory.Exists(directory))
Directory.CreateDirectory(directory);
}
catch (Exception ex)
{
var metaData = new Dictionary<string, string>
{
{ "DatabaseFilePath", databaseFilePath },
{ "Directory", directory }
};
LoggingService.ReportException(ex, metaData);
throw;
}
return CreateAsyncDbConnection(databaseFilePath);
}
In case of the exception both databaseFilePath and directory have proper values and are not null.
The databaseFilePath is created with Path.Combine() and consists of the following parts:
- storage path: sdcard (determined with
Environment.ExternalStorageDirectory.AbsolutePath) - bundle identifier: com.mycompany.myapp (determined with
ApplicationInfo.PackageName) - database folder: database (hardcoded string)
- database file name: mydatabasefile.db3 (hardcoded string)
and looks like this:
/sdcard/com.mycompany.myapp/database/mydatabasefile.db3
The directory is the same but without the database file name:
/sdcard/com.mycompany.myapp/database
The exception does not occur a second time when the app is started again on the same device.
We also track our crashes with AppCenter. This is the reported stack trace:
FileSystem.CreateDirectory (System.String fullPath)
Directory.CreateDirectory (System.String path)
DatabaseConnectionProviderBase.CreateDatabaseConnection (System.String databaseFilePath)