I have my first smartphone since one week and try make a App with Xamarin.
I use SQLite with EntityFrameworkCore to store data.
It is work fine, but to debug easier I want use a SQLite browser.
The database file path is 'data/data/{AppName}/Database.db'.
I debug from a physic device by USB, but when I explore the device with Windows Explorer I cannot find the SQLite DB file. The 'data/data' folder is not available. Then I can not use a SQLite browser to see the data.
In this post, the author use a Android emulator and can see 'data/data' folder :
https://blog.xamarin.com/building-android-apps-with-entity-framework/
But I prefer use a real device.
Have you a solution?
A solution from the MikeT, in development store the db file in available folder like this :
public static string DatabasePath
{
get
{
var dbFolder = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
var fileName = "database.db";
var dbFullPath = Path.Combine(dbFolder, fileName);
return dbFullPath;
}
}
In production, copy the db file to a available folder.
One a real device you would, I believe, need to root the device to directly access the data.
However, what you could do is to copy the database file elsewhere e.g. to external storage. In following is the core process that I use:-
try {
FileInputStream fis = new FileInputStream(dbfile);
OutputStream backup = new FileOutputStream(backupfilename);
//byte[] buffer = new byte[32768];
int length;
while((length = fis.read(buffer)) > 0) {
backup.write(buffer, 0, length);
}
backup.flush();
backup.close();
fis.close();
catch (IOException e) {
e.printStackTrace();
confirmaction = false;
}
I use the following to get the pathname for backupfilename:-
File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),subdirectory);
this.directory = dir.getPath();
I then add the actual filename (which is user input).
Note! I do checks to determine that EXTERNAL storage is mounted etc.
To get the database path i use:-
String dbfilename = this.getDatabasePath(
DBConstants.DATABASE_NAME).getPath();
dbfile = new File(dbfilename);
This is of course Java, but I'd assume that it could be converted/adapted to suit. The crux of the answer is to get the database file into a place from which you can access it.
Call the ExtractDb method from your activity
public void ExtractDB()
{
var szSqliteFilename = "databasename.db3";
var szSourcePath = new FileManager().GetLocalFilePath(szSqliteFilename);
var szDatabaseBackupPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/databasename_Backup.db3";
if (File.Exists(szSourcePath))
{
File.Copy(szSourcePath, szDatabaseBackupPath, true);
Toast.MakeText(this, "Copied", ToastLength.Short).Show();
}
}
Get path to the android device storage as shown below
public class FileManager
{
public string GetLocalFilePath(string filename)
{
string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
return Path.Combine(path, filename);
}
}
you need to add the android.permission.WRITE_EXTERNAL_STORAGE permission in your manifest file.
Related
i was using GetExternalStoragePublicDirectory but is deprecated now, it gets back the standard path "/storage/emulated/0/Download" but from Android 12 i can save, load only the file stored from my app, if i add the same file renamed by pc is "filtered" and not accessible, it looks like not present!
i store a txt file from my app, how can i work around to access again to download external public folder?
I have create a sample to test the GetExternalStoragePublicDirectory method and create a txt file in the Download folder. Here is the MainActivity's code:
Button write = this.FindViewById<Button>(Resource.Id.buttonwrite);
Button read = this.FindViewById<Button>(Resource.Id.buttonread);
write.Click += (s, e) =>
{
var path = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDownloads);
var file = Path.Combine(path + "/app.txt");
using (System.IO.FileStream os = new System.IO.FileStream(file, System.IO.FileMode.OpenOrCreate))
{
string temp = "this is test string";
byte[] buffer = Encoding.UTF8.GetBytes(temp);
os.Write(buffer, 0, buffer.Length);
}
Intent intent = new Intent(DownloadManager.ActionViewDownloads);
StartActivity(intent);
// this line code can open the download folder and view all the files in it. When the user click the file, it will be open
};
read.Click += (s, e) =>
{
var path = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDownloads);
var file = Path.Combine(path + "/app.txt");
/* using (System.IO.FileStream os = new System.IO.FileStream(file, System.IO.FileMode.OpenOrCreate))
{
StreamReader streamReader = new StreamReader(os);
var content = streamReader.ReadToEnd();
} */
Intent intent = new Intent(Intent.ActionOpenDocument);
intent.AddCategory(Intent.CategoryOpenable);
intent.SetType("text/*");
intent.PutExtra(DocumentsContract.ExtraInitialUri, Uri.Parse(file));
StartActivityForResult(intent, 2);
//This code can open the file picker and let the user to choose a file
};
The app.txt file can still be read when I renamed as New.txt by the file manager. Just change var file = Path.Combine(path + "/app.txt"); to var file = Path.Combine(path + "/New.txt"); and use the code in the /* can read it. So if the file was created by your app, your app can access it even though the file has been renamed by the uesr. But you can access the file in the public folder which was not created by your app.
In addidion, if you don't have to push your app to the google play, you can use the access all file permission according to my old answer in this link and the answer about the deprecated GetExternalStoragePublicDirectory.
I have to export files from my application and looking for a solution, where I can save files, to give the user the possibility to open them.
I tried already getFilesDir().getPath() which worked well, until I realized that the folder can't open from a real device (/data/user/0/com.myapplication.example/files) since the /data path is just a storage area for the application.
What are the alternatives?
You should have a look here https://developer.android.com/training/data-storage
I'm not sure what file type you are trying to store however what you have tried stores the file withing the applications directory and not the devices. To combat this I would look under either Media or Documents and other files again in the above link. I would be able to be of further assistance if I knew what file type you are trying to store. Hope this helps you in some way.
This is a function to store a float array to the phone external storage. Pass the file name.extension in the String name. You could modify it to export your file.
public static void save(float[] input_array, String name)
{
final String TAG2 = "->save()";
String string_array = Arrays.toString(input_array);
String fullName = Environment.getExternalStorageDirectory().getPath() + "/SercanFolder/" + name;
String path = Environment.getExternalStorageDirectory().getPath() + "/SercanFolder";
File folder = new File(path);
if(!folder.exists())
{
folder.mkdirs();
}
BufferedWriter buf;
try
{
buf = new BufferedWriter(new FileWriter(fullName));
buf.write(string_array,0,string_array.length());
buf.close();
Log.d(TAG+TAG2, "array saved as document. ");
}
catch (IOException e)
{
Log.e(TAG+TAG2, "problems while saving the file. ");
}
}
The suggestion with getExternalStorage().getPath() (Thanks to blackapps) helped me to save the pdf in a folder, which can be opened in the file manager.
My app should save files to a place where, when you connect your phone/tablet to a computer, you can see them through the system file explorer.
This is the way I implemented file writing:
protected String mDir = Environment.DIRECTORY_DOCUMENTS;
protected File mPath = Environment.getExternalStoragePublicDirectory(mDir);
protected void writeLogFile(String filename) {
File f = new File(mPath, filename + ".txt");
f.getParentFile().mkdirs();
try (BufferedWriter bw = new BufferedWriter(new FileWriter(f, false))) {
// Details omitted.
} catch (Exception e) {
e.printStackTrace();
return;
}
makeText("Wrote " + f.getAbsolutePath());
}
This is what I see when I connect my Sony Xperia Z4 tablet to Windows (notice missing documents folder):
This is the directory to which the file is written (using above implementation):
What is wrong with my implementation?
What is wrong with my implementation?
MediaStore has not discovered your newly-created files yet. What you see in Windows — and in many on-device "gallery" apps — is based on what MediaStore has indexed.
Use MediaScannerConnection and its scanFile() method to tell MediaStore about your file, once you have written out your data to disk:
public void scanFile(Context ctxt, File f, String mimeType) {
MediaScannerConnection
.scanFile(ctxt, new String[] {f.getAbsolutePath()},
new String[] {mimeType}, null);
}
or, in Kotlin:
fun scanFile(ctxt: Context, f: File, mimeType: String) {
MediaScannerConnection.scanFile(ctxt, arrayOf(f.getAbsolutePath()), arrayOf(mimeType), null)
}
I have got a problem with backup database in my app. I am working on Android 2.2.3 and this has sd card installed. Making copy of the database works fine. The problem occures when I'am testing my app on the phone with internal memory enought big like sd cards (Nexus 32gb). In this scenario my method doesn't work extracting file to sd card because it doesn't (sd card) exist. How to make copy of database to internal independed location? I've tried:
File outPut = new File(Environment.getRootDirectory().toString() + "/myfolder/");
but got permission denied and can not create folder with data. Can anyone show correct way?
EDITED:
I don't get it. I'd like to make new folder with dataBackup. I've defined correct location for that but it says that can not find file. SDCard is present. Why it can not create that folder - "/storeUGif/databaseName.db".?
Here is absolute path for destination folder:
public static final String OUTPUT_BACKUP_DATABASE = Environment.getExternalStorageDirectory().getAbsolutePath() + "/storeUGif/" + SqliteHelper.DATABASE_NAME;
if(isSdPresent())
{
//File outPut = new File(Environment.getExternalStorageDirectory().getAbsolutePath().toString()+"/StoreUGif/"+SqliteHelper.DATABASE_NAME);
File outPut = new File(Tools.OUTPUT_BACKUP_DATABASE);
File storeUGif = new File(Environment.getExternalStorageDirectory().getAbsolutePath().toString());
storeUGif.mkdir();
File currentDB = getApplicationContext().getDatabasePath(SqliteHelper.DATABASE_NAME);
FileInputStream is = new FileInputStream(currentDB);
OutputStream os = new FileOutputStream(outPut);
byte[] buffer = new byte[1024];
while (is.read(buffer) > 0) {
os.write(buffer);
}
os.flush();
os.close();
is.close();
}
else
{
Toast.makeText(this, "SDCard is unvailable", Toast.LENGTH_SHORT).show();
}
Use Environment.getExternalStorageDirectory() to get a valid path.
Despite its name, it will return the default storage, either the external or (if missiing) the internal one.
For reference: http://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()
I've been using the following code, but intuitively I see it's not too safe. Will it work flawlessly in every device? This code copies to internal memory my main database (100 kB) in the first app run. Thanks for your time.
private void CopyDBtoInternal() {
String path = "/data/data/com.myproject/databases/";
String DB_DESTINATION = "/data/data/com.myproject/databases/sample.db";
// Check if the database exists before copying
boolean initialiseDatabase = (new File(DB_DESTINATION)).exists();
if (initialiseDatabase == false) {
//create folders
File db_folder = new File(path);
db_folder.mkdirs();
AssetManager assetManager = getApplicationContext().getAssets();
try {
InputStream is = assetManager.open("sample.db");
// Copy the database into the destination
OutputStream os = new FileOutputStream(DB_DESTINATION);
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0){
os.write(buffer, 0, length);
}
os.flush();
os.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
AlertDialog.Builder dialogo = new AlertDialog.Builder(AppGuiaDeBulas.this);
dialogo.setTitle("Alerta");
dialogo.setMessage("It was not possible to save database. Error #001");
dialogo.setNeutralButton("OK", null);
dialogo.show();
}
}
}
Check out this part of the article on writing to storage.
If you're using API Level 8 (Froyo) or greater, use getExternalFilesDir() to open a File that represents the external storage directory where you should save your files. This method takes a type parameter that specifies the type of subdirectory you want, such as DIRECTORY_MUSIC and DIRECTORY_RINGTONES (pass null to receive the root of your application's file directory). This method will create the appropriate directory if necessary. By specifying the type of directory, you ensure that the Android's media scanner will properly categorize your files in the system (for example, ringtones are identified as ringtones and not music). If the user uninstalls your application, this directory and all its contents will be deleted.
If you're using API Level 7 or lower, use getExternalStorageDirectory(), to open a File representing the root of the external storage. You should then write your data in the following directory:
/Android/data//files/
The is your Java-style package name, such as "com.example.android.app". If the user's device is running API Level 8 or greater and they uninstall your application, this directory and all its contents will be deleted.
http://developer.android.com/guide/topics/data/data-storage.html#AccessingExtFiles