I have some paths on sd card on Android 7, which are unwritable using instant access requiring, so I have to use StorageVolume.createAccessIntent and therefore use DocumentFile later instead of File. But the problem is that I need to use File, because db lib(realm), that I'm using, simply uses File object to store data. So the point is that I have to createDirectory and this directory(it's path) has to have writing access. How to do this using DocumentFile.createDirectory() or something like that?
So the point is that I have to createDirectory and this directory(it's path) has to have writing access
That is not supported.
The only direct filesystem access that you have to removable storage is via getExternalFilesDirs(), getExternalCacheDirs(), and getExternalMediaDirs() (all methods on Context). If these return 2+ items, the second and subsequent ones are locations on removable storage that are unique to your app and which you can read/write using classic File objects.
Otherwise, keep your Realm database on external storage, then copy it to removable storage at some appropriate point (e.g., user-initiated "export" or "backup" operation).
Related
As we all know starting Android Q (API=29) introduced new Scoped Storage concept, which basically prevents access to external files/dirs, except media files. Namely:
Programmer can use internal/app specific storage (no limits) - getFilesDir()
The only external storage can be accessed is via getExternalFilesDir(), but during app uninstall data will be deleted
There's option to access external storage via MediaStore, but it works only for media files
App still can read any external file via: getContentResolver().openInputStream(uri)
In my case I have app, which stores user data in SQLite database in app specific directory, database size can be up-to several gigs.
In all previous versions of my app users used to backup data to external storage/SD/USB and transfer those data to their new device, so they could continue to use data (it's encrypted database containing any kind of private data, including audio/video/documents and so on).
Question: how can I backup this database? I couldn't manage to find appropriate way to save/backup data to any external storage...
P.S. Android autobackup service is unworkable due to the size of database.
I have a SQLite database on my sdcard (/storage/sdcard/MyDir/mydb.sqlite) and try to write some data in it. Due to the Storage Access Framework I can not access the file directly and I need to get write access like it is described here. This grants me write access via a DocumentFile.
However, the database needs to accessed via JDBC. JDBC requires a String to the database file to establish a database connection. This leads to the following problems:
If I use the Java-Path I can access the database, but I have no writing permission. Even if the access was granted like described above.
If I use the Uri of the DocumentFile (having writing permission) JDBC does not find the database file.
I can place my database in the private directory of the application on the sdcard (/storage/sdcard/Android/data/my.application.package/) where I have writing permission. However, I would like to store the database outside that directory, since the database should be accessed by multiple applications.
I tried this suggestion, which works on the device storage, however does not work on the sdcard. On the sdcard I get this stacktrace:
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 1294 SQLITE_CANTOPEN_ENOENT[1294]): Could not open database
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:284)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:705)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:272)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:239)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:1292)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:1247)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:930)
at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:947)
When I access the database on the device storage (internal storage and external storage) I can write the database. Only if I access the database on the sdcard I have no writing permission.
Is there any possibility to get write access to specific files on the sdcard based on java.io.File like it is possible for DocumentFile?
Does anybody have a different idea how I can access the data on the sdcard with writing permission?
I have a SQLite database on my sdcard (/storage/sdcard/MyDir/mydb.sqlite)
Using removable storage as a transfer location for a SQLite database is OK. For example, using removable storage for backup and restore operations is fine.
However, for a live database, removable storage is very risky. On many devices, removable storage is removable, and you will suffer catastrophic problems if the user removes the storage while you are trying to write to your database.
And, as you are discovering, using removable storage for a live data is impractical.
the database needs to accessed via JDBC
Android has a built-in SQLite database API. Attempting to use Android's half-baked JDBC classes for accessing a SQLite database is very strange.
When I access the database on the device storage (internal storage and external storage) I can write the database
You will encounter problems on Android 10 and higher, as you no longer have direct filesystem access to most of external storage.
Is there any possibility to get write access to specific files on the sdcard based on java.io.File like it is possible for DocumentFile?
No, sorry. You do not have filesystem access to arbitrary locations on removable storage as of Android 4.4. Android 10 extends that to arbitrary locations on external storage. Either:
Limit yourself to the directories that you can access, or
Use removable storage only for backup/restore operations, with the live database in a more conventional location (getDatabasePath() on Context)
I want to create SQL db file on USB (otg) device. The problem is that on newer devices I access the USB using SAF so no real file path or handle any more.
All android sqlite openOrCreateDatabase methods need file or path which is not longer possible with SAF/DocumentFile.
The other options I was thinking about using sqlite alternatives but seems Realm doesn't support this either?
Any other ideas?
So I assume sqlite API will soon be updated to support DocumentFile or Uri?
To make it clear app works with large data on an usb stick, app also needs db to store some info on the usb. Of course I can alwasy create on device and latter copy on usb, but if the process stops in the middle data will be lost?
You can not store SQLite databases using SAF because SQLite does not support opening databases on (SAF) Uris, and probably never will for reasons explained in the linked answer.
You need to create the database in an accessible location, perform any read/write operations and then copy the database onto the USB drive. To avoid data loss, don't overwrite the target file (if it exists) and instead use a temporary file and rename that only after the complete operation is successful.
If you look at the all available storage access methods, the only other option is Context#getExternalFilesDirs which should not work because...
The returned paths do not include transient devices, such as USB flash drives connected to handheld devices.
However, for the devices I tested on this does not seem to be true, e.g. you actually can access USB devices using getExternalFilesDirs(). E.g. if you have a volume uuid 00A1-CC00 you can access the SAF Uri content://com.android.externalstorage.documents/tree/00A1-CC00%3A/document/00A1-CC00%3AAndroid%2Fdata%2Fcom.example%2Ffiles as /storage/00A1-CC00/Android/data/com.example/files.
If you absolutely need to do database operations without a temporary internal file, you may be able to use an h2 in memory database. This would require a modified BACKUP TO statement to allow writing to a SAF OutputStream.
A simple question. By default android doesn't allow 3rd party apps to write to removable sd card.
But in Android 5.0 I can request for permission to write to removable sdcard and write any file in that directory.
So how to do that? I need an output stream to write to the file.
I can request for permission to write to external sdcard and write any file in that directory.
Not really.
On Android 4.4+, you can use getExternalFilesDirs(), getExternalCacheDirs(), and getExternalMediaDirs(). If those return 2+ items, the second and subsequent ones will be locations on removable storage.
On Android 5.0+, you can use ACTION_OPEN_DOCUMENT_TREE, to ask the user to grant you access to a document tree. That could be the root of removable storage... or anything else the user wants to use. This gives you a Uri back, which you can use with DocumentFile and the rest of the Storage Access Framework. It does not give you filesystem access (e.g., via File).
On Android 7.0+, you can use StorageManager and StorageVolume to ask for access to a removable storage volume. Once again, though, you get a Uri back to use with DocumentFile, ContentResolver, etc -- you do not get filesystem access.
How do I grant Read/Write Permissions to internal storage of my application to TextToSpeech/MediaPlayer?
TextToSpeech.synthesizeToFile return -1 when I attempt to store file in internal storage of application ( for folder like /data/data/my.mycode.mydata/ )
It works for SD card when I give permission for it. I think I get error ( return value -1 ) since TextToSpeech/MediaPlayer does not have permission for internal storage file creation.
How do I provide it? probabally through manifest.xml?
You have two options.
The better approach is to create a ContentProvider that will serve your files, and use the associated content:// Uri values when working with "TextToSpeech/MediaPlayer". Here is a sample project demonstrating an app serving up a PDF file, copied out of the project's assets, to be viewed by a PDF viewer on the device.
Alternatively, create the file using openFileOutput() and MODE_WORLD_READABLE.