I'm storing user data in ApplicationData folder. Its path is obtained with :
userDataPath = System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), "userData");
This variable is equal to /data/user/0/APPNAME/files/.config/userData.
Each time I rebuild the project, if I delete the userData file with File.Delete(userDataPath), I can successfully create the file, write and read to it several times. I can indeed check the created file in /data/data/APPNAME/files/.config/userData.
I check in /data/data/.../.config/userData and not in /data/user/.../.config/userData because apparently the latter is a symlink to the former, so it should be equivalent ? Moreother I don't have access to /data/user/.../.config/userData.
The problem is that if I rebuild the app without deleting the file, I got an unhandled exception at the following Deserialization (which worked fine before) :
if (File.Exists(userDataPath))
{
Stream reader = new FileStream(userDataPath, FileMode.Open);
Console.WriteLine(userDataPath);
userData = (UserData)serializer.Deserialize(reader); // ERROR HERE
reader.Close();
}
It is very strange because the file located at /data/data/APPNAME/files/.config/userData does not exist but since File.Exists(userDataPath) is true, the file located at /data/user/0/APPNAME/files/.config/userData does exist.
So how can this be explained and is this the correct way to store data in ApplicationData folder ?
After switching to another SpecialFolder (LocalApplicationData), I can't reproduce the unhandeld exception anymore (even when switching back to ApplicationData).
I'll keep this post updated if it ever happens again.
I am in the process of implementing access to a SQLite database via SQLCipher in my hybrid Cordova app for Android which uses one custom plugin (i.e. written by me). The SQLCipher documentation - as well as other tutorials on using SQLite in Android - keep referring to Context.getDatabasePath. In my plugin code I store other app files and make extensive use of Context.getFilesDir. In what way is getDatabasePath different from getFilesDir. For instance, does it promise a better chance that the database will persist and not somehow get dumped because the OS decides to create "some more room" by deleting some files stored in Context.getFilesDir?
Both are resolved to the same directory. getDatabasePath calls getDatabasesDir.
getDatabasesDir:
private File getDatabasesDir() {
synchronized (mSync) {
if (mDatabasesDir == null) {
if ("android".equals(getPackageName())) {
mDatabasesDir = new File("/data/system");
} else {
mDatabasesDir = new File(getDataDir(), "databases");
}
}
return ensurePrivateDirExists(mDatabasesDir);
}
}
getFilesDir:
#Override
public File getFilesDir() {
synchronized (mSync) {
if (mFilesDir == null) {
mFilesDir = new File(getDataDir(), "files");
}
return ensurePrivateDirExists(mFilesDir);
}
}
Notice the returned File is resolved by ensurePrivateDirExists in both method, which has the same input directory resolved by getDataDir.
getDataDir
Returns the absolute path to the directory on the filesystem where all
private files belonging to this app are stored.
So, there is NO difference in your case.
Do not forget the returned path can change, as the doc says:
The returned path may change over time if the calling app is moved to
an adopted storage device, so only relative paths should be persisted.
I am trying to create a SQLIte database on Internal Storage in my Xamarin application. I am creating a system for an offline environment where at least 3 applications are inter-connected with shared data. So if one application creates some data the other application should be able to read that.
The Database project is a Portable Class Library which I plan to include in all three applications.
My DbHelper is as follows:
public Database()
{
string folder = "/data/data/Anchor.Main";
_dbPath = System.IO.Path.Combine(folder, "Anchor.db");
try
{
if (!System.IO.Directory.Exists(folder))
{
System.IO.Directory.CreateDirectory(folder); //Getting error here
}
_connection = new SQLiteConnection(_dbPath);
_connection.CreateTable<Orders>();
_connection.CreateTable<Items>();
}
catch(Exception ex)
{ }
}
I get error which says
Access to the path "/data/data/Anchor.Main" is denied.
Following is the stack trace
at System.IO.Directory.CreateDirectoriesInternal (System.String path)
[0x0004b] in <3fd174ff54b146228c505f23cf75ce71>:0 at
System.IO.Directory.CreateDirectory (System.String path) [0x00075] in
<3fd174ff54b146228c505f23cf75ce71>:0 at
anchorapp.db.Helper.Database..ctor () [0x0002e]
I understand this is because of the permissions, but what permissions do I need to set in order to write to the Internal storage from a PCL?
You are accessing Android system folder of "/data/data/Anchor.Main".
Your app internal storage will be in
/data/data/#PACKAGE_NAME#/files
You can use the following code to get the folder to store the database:
// Equal to /data/data/#PACKAGE_NAME#/files
var homePath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
_dbPath = System.IO.Path.Combine(homePath, "Anchor.db");
_connection = new SQLiteConnection(_dbPath);
Android and iOS does not work that way. Each platform keeps apps in a sandboxed environment. If you want to create and store data in your app you need to create the path like the following sample:
var docFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
_dbPath = System.IO.Path.Combine(docFolder, "Anchor.db");
Also set the permissions ReadExternalStorage and WriteExternalStorage in your Android project
Instead of writing to a private folder, you could create the database in a public one. To do so the docFolder would change to:
var docFolder = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, "YourDirectoryName");
Please be advised, that if you go that way everyone can see and open the database.
I did this by creating a sharedId within my projects and using the SharedContext to access the databases created by other apps
I have some level definitions in xml format (with .txt extension) inside (without any subfolders) my project's rescources folder
I for more scalability, I have a plain text file naming all these level definition XMLs
I read that file using
TextAsset WorldList = (TextAsset)Resources.Load("WorldList");
And then I load the needed world:
TextAsset TA = (TextAsset)Resources.Load(/*"LevelDefs/" +*/ Worlds[worldToload]);
xps.parseXml(TA.text);
loadLevel(levelToLoad);
(you see that I have moved these rescources out of subfolder to reduce the chance of them not loading)
worldToload here is the index number of that world
program works fine on windows but nothing loads on my android test device.
I seem to have problems debugging on device so I only guess something went wrong in loading phase.
any suggestions?
From Unity Documentation:
Most assets in Unity are combined into the project when it is built.
However, it is sometimes useful to place files into the normal
filesystem on the target machine to make them accessible via a
pathname. An example of this is the deployment of a movie file on iOS
devices; the original movie file must be available from a location in
the filesystem to be played by the PlayMovie function.
Any files placed in a folder called StreamingAssets in a Unity project
will be copied verbatim to a particular folder on the target machine.
You can retrieve the folder using the Application.streamingAssetsPath
property. It’s always best to use Application.streamingAssetsPath to
get the location of the StreamingAssets folder, it will always point
to the correct location on the platform where the application is
running.
So below snippet should work:
// Put your file to "YOUR_UNITY_PROJ/Assets/StreamingAssets"
// example: "YOUR_UNITY_PROJ/Assets/StreamingAssets/Your.xml"
if (Application.platform == RuntimePlatform.Android)
{
// Android
string oriPath = System.IO.Path.Combine(Application.streamingAssetsPath, "Your.xml");
// Android only use WWW to read file
WWW reader = new WWW(oriPath);
while ( ! reader.isDone) {}
realPath = Application.persistentDataPath + "/Your"; // no extension ".xml"
var contents = System.IO.File.ReadAll(realPath);
}
else // e.g. iOS
{
dbPath = System.IO.Path.Combine(Application.streamingAssetsPath, "Your.xml");
}
Thanks to David I have resolved this problem.
for more precision I add some small details:
1-As David points out in his answer (and as stated in unity documentations), we should use StreamingAssets if we want to have the same folder structure. One should use Application.streamingAssetsPathto retrieve the path.
However, files are still in the apk package in android's case, so they should be accessed using unity android's www class.
a good practice here is to create a method to read the file (even mandatory if you are going to read more than one file)
here is one such method:
private IEnumerator LoadDataFromResources(string v)
{
WWW fileInfo = new WWW(v);
yield return fileInfo;
if (string.IsNullOrEmpty(fileInfo.error))
{
fileContents = fileInfo.text;
}
else
fileContents = fileInfo.error;
}
This is a coroutine, and to use it we need to call it using
yield return StartCoroutine(LoadDataFromResources(path + "/fileName.ext"));
Yet another remark: we can not write into this file or modify it as it's still inside the apk package.
I've created a sqlite database programmatically with the default way of extending SQLiteOpenHelper and overriding onCreate(). This way the db gets created on the fly when needed.
I'd like to check the contents of the db file on my OS X machine with a sqlite browser.
I know the name of the db file, but I can't find it on the device. I've connected to the device via USB and looked with finder and terminal, but I just can't find the db file.
What is the default location for a sqlite databases on an android device?
You can find your created database, named <your-database-name>
in
//data/data/<Your-Application-Package-Name>/databases/<your-database-name>
Pull it out using File explorer and rename it to have .db3 extension to use it in SQLiteExplorer
Use File explorer of DDMS to navigate to emulator directory.
For this, what I did is
File f=new File("/data/data/your.app.package/databases/your_db.db3");
FileInputStream fis=null;
FileOutputStream fos=null;
try
{
fis=new FileInputStream(f);
fos=new FileOutputStream("/mnt/sdcard/db_dump.db");
while(true)
{
int i=fis.read();
if(i!=-1)
{fos.write(i);}
else
{break;}
}
fos.flush();
Toast.makeText(this, "DB dump OK", Toast.LENGTH_LONG).show();
}
catch(Exception e)
{
e.printStackTrace();
Toast.makeText(this, "DB dump ERROR", Toast.LENGTH_LONG).show();
}
finally
{
try
{
fos.close();
fis.close();
}
catch(IOException ioe)
{}
}
And to do this, your app must have permission to access SD card, add following setting to your manifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Not a brilliant way, but works.
The Context contains many path functions: Context.getXXXPath()
One of them is android.content.Context.getDatabasePath(String dbname) that returns the absolute path of a database called dbname.
Context ctx = this; // for Activity, or Service. Otherwise simply get the context.
String dbname = "mydb.db";
Path dbpath = ctx.getDatabasePath(dbname);
The returned path, in this case, would be something like:
/data/data/com.me.myapp/databases/mydb.db
Note that this path is autogenerated if using SQLiteOpenHelper to open the DB.
If you're talking about real device /data/data/<application-package-name> is unaccessible. You must have root rights...
This is and old question, but answering may help others.
Default path where Android saves databases can not be accesed on non-rooted devices. So, the easiest way to access to database file (only for debugging environments) is to modify the constructor of the class:
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
MySQLiteOpenHelper(Context context) {
super(context, "/mnt/sdcard/database_name.db", null, 0);
}
}
Remember to change for production environments with these lines:
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
MySQLiteOpenHelper(Context context) {
super(context, "database_name.db", null, 0);
}
}
/data/data/packagename/databases/
ie
/data/data/com.example.program/databases/
A SQLite database is just a file. You can take that file, move it around, and even copy it to another system (for example, from your phone to your workstation), and it will work fine. Android stores the file in the /data/data/packagename/databases/ directory. You can use the adb command or the File Explorer view in Eclipse (Window > Show View > Other... > Android > File Explorer) to view, move, or delete it.
well this might be late but it will help.
You can access the database without rooting your device through adb
start the adb using cmd and type the following commands
-run-as com.your.package
-shell#android:/data/data/com.your.package $ ls
cache
databases
lib
shared_prefs
Now you can open from here on.
If you name your db as a file without giving a path then most common way to get its folder is like:
final File dbFile = new File(getFilesDir().getParent()+"/databases/"+DBAdapter.DATABASE_NAME);
where DBAdapter.DATABASE_NAME is just a String like "mydatabase.db".Context.getFilesDir() returns path for app's files like: /data/data/<your.app.packagename>/files/ thats why you need to .getParent()+"/databases/", to remove "files" and add "databases" instead.
BTW Eclipse will warn you about hardcoded "data/data/" string but not in this case.
By Default it stores to:
String DATABASE_PATH = "/data/data/" + PACKAGE_NAME + "/databases/" + DATABASE_NAME;
Where:
String DATABASE_NAME = "your_dbname";
String PACKAGE_NAME = "com.example.your_app_name";
And check whether your database is stored to Device Storage. If So, You have to use permission in Manifest.xml :
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
You can access it using adb shell how-to
Content from above link:
Tutorial : How to access a Android database by using a command line.
When your start dealing with a database in your program, it is really
important and useful to be able to access it directly, outside your
program, to check what the program has just done, and to debug.
And it is important also on Android.
Here is how to do that :
1) Launch the emulator (or connect your real device to your PC ). I
usually launch one of my program from Eclipse for this. 2) Launch a
command prompt in the android tools directory. 3) type adb shell. This
will launch an unix shell on your emulator / connected device. 4) go
to the directory where your database is : cd data/data here you have
the list of all the applications on your device Go in your application
directory ( beware, Unix is case sensitive !! ) cd
com.alocaly.LetterGame and descend in your databases directory : cd
databases Here you can find all your databases. In my case, there is
only one ( now ) : SCORE_DB 5) Launch sqlite on the database you want
to check / change : sqlite3 SCORE_DB From here, you can check what
tables are present : .tables 6) enter any SQL instruction you want :
select * from Score;
This is quite simple, but every time I need it, I don't know where to
find it.
Do not hardcode path like //data/data/<Your-Application-Package-Name>/databases/<your-database-name>. Well it does work in most cases, but this one is not working in devices where device can support multiple users. The path can be like //data/user/10/<Your-Application-Package-Name>/databases/<your-database-name>. Possible solution to this is using context.getDatabasePath(<your-database-name>).
If your application creates a database, this database is by default saved in the directory DATA/data/APP_NAME/databases/FILENAME.
The parts of the above directory are constructed based on the following rules. DATA is the path which the Environment.getDataDirectory() method returns. APP_NAME is your application name. FILENAME is the name you specify in your application code for the database.
You can find your database file :
Context.getDatabasePath(getDatabaseName())
getDatabaseName from class SQLiteOpenHelper
In kotlin you can find it in this way:
val data: File = Environment.getDataDirectory()
val currentDBPath = "//data//$packageName//databases//"
val destDir = File(data, currentDBPath)
You can also check whether your IDE has a utility like Eclipse's DDMS perspective which allows you to browse through the directory and/or copy files to and from the Emulator or a rooted device.
Define your database name like :
private static final String DATABASE_NAME = "/mnt/sdcard/hri_database.db";
And you can see your database in :
storage/sdcard0/yourdatabasename.db
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
MySQLiteOpenHelper(Context context) {
super(context, "/mnt/sdcard/database_name.db", null, 0);
} }
Do not hardcode "/sdcard/"; use Environment.getExternalStorageDirectory().getPath() instead
#Shardul's answer is correct.
Besides that, new Android Studio has a tool called: App Inspection, which you can view database directly.
Here is the version of Android Studio:
Android Studio Arctic Fox | 2020.3.1 Patch 3
Build #AI-203.7717.56.2031.7784292, built on October 1, 2021