I am using the following code that was posted somewhere on Stack Overflow and modified for my purposes:
try {
File sd = Environment.getExternalStorageDirectory();
File data = Environment.getDataDirectory();
if (sd.canWrite()) {
String currentDBPath = "//data//"+ "com.exercise.AndroidSQLite" +"//databases//"+"MY_DATABASE";
String backupDBPath = "/temp/MY_DATABASE";
File currentDB = new File(data, currentDBPath);
File backupDB = new File(sd, backupDBPath);
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast.makeText(getBaseContext(), backupDB.toString(), Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
}
}
So the error I get when I try to access it is:
java.io.FileNotFoundException: /data/data/com.exercise.AndroidSQLite/databases/MY_DATABASE: open failed: EACCES (Permission Denied)
I am trying to copy this file without rooting my tablet. The write external storage directory permission is set in the application; I just can't get around this error. Would appreciate help on resolving this issue, it's driving me mad
I am backing up my database in my android application and it works fine. You can only access the database file if you are the owner of it, meaning your application created it.
I think your path is wrong, I have this in my app:
private static final String DATABASE_NAME = "my.db.name";
public File getBackupDatabaseFile() {
File dir = new File(getStorageBaseDirectory().getAbsolutePath() + "/backup");
if (!dir.exists()) {
dir.mkdirs();
}
return new File(dir, DATABASE_NAME);
}
public final boolean backupDatabase() {
File from = mContext.getDatabasePath(DATABASE_NAME);
File to = this.getBackupDatabaseFile();
try {
FileUtils.copyFile(from, to);
return true;
} catch (IOException e) {
// TODO Auto-generated catch block
Log.e(TAG, "Error backuping up database: " + e.getMessage(), e);
}
return false;
}
And FileUtils.copyFIle is this:
public static void copyFile(File src, File dst) throws IOException {
FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dst);
FileChannel fromChannel = null, toChannel = null;
try {
fromChannel = in.getChannel();
toChannel = out.getChannel();
fromChannel.transferTo(0, fromChannel.size(), toChannel);
} finally {
if (fromChannel != null)
fromChannel.close();
if (toChannel != null)
toChannel.close();
}
}
You are using "MY_DATABASE" literally when you probably actually want to use it as a variable...
Remove the quotes from around it and see if that doesn't solve your problem.
Related
In my App i need to implement restoring room database that i have exported to local storage. i have managed to copy all 03 database files (.db -shm and wal) using get getDatabasePath(DATABASE_NAME).getAbsolutePath(). For replacing it back, i am copying these exported files back to original database path, which works fine, but no data is showing when i access it from inside the app. The exported database is clearly showing all the table with DB Browser tool. I am not sure why its not working.This is a backup button, which generates backup files. I am not sure if i am approaching it wrong or there is something wrong in my code.
backpathbutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String currentDBPath =
getDatabasePath(DATABASE_NAME).getAbsolutePath();
String backupDBPath = "my_db";
File sd = Environment.getExternalStorageDirectory();
File data = Environment.getDataDirectory();
String rot = Environment.getExternalStorageDirectory().toString();
File currentDB = new File(currentDBPath);
File backupDB = new File(sd, backupDBPath);
if (currentDB.exists()) {
try {
db.close();
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
backupDB = new File(sd, backupDBPath+"-shm");
src = new FileInputStream(currentDB+"-shm").getChannel();
dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
backupDB = new File(sd, backupDBPath+"-wal");
src = new FileInputStream(currentDB+"-wal").getChannel();
dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();}
catch (IOException e) {
e.printStackTrace();
}}} });
Here is the restore button
restorebutton.setOnClickListener(v -> {
db.close();
String back=
getDatabasePath(DATABASE_NAME).getAbsolutePath();
File sd = Environment.getExternalStorageDirectory();
File data = Environment.getDataDirectory();
String current = "my_db";
String currentsh = "my_db-shm";
String currentwl = "my_db-wal";
String filepath= sd+"/"+current;
String shmfile= sd+"/"+currentsh;
String currenwl= sd+"/"+currentwl;
File dest=new File(back);
Log.d(TAG, "Following files are in absolute path " + dest.list()); // returning null
try {
copyFile(filepath,dest);
copyFile(shmfile,dest);
copyFile(currenwl,dest);
Log.d(TAG, "Copied Sucessfully "); // it Copies without error
}
catch (IOException e) {
e.printStackTrace();
}
});
}
Here is my copy file function
public void copyFile(String src, File dst) throws IOException
{
FileChannel inChannel = new FileInputStream(String.valueOf(src)).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel();
try
{
inChannel.transferTo(0, inChannel.size(), outChannel);
}
finally
{
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
}
}
After returning back to my MainActivity, restored data is not showing, even after closing and reopening the app again.
I am trying to restore a database from the phone storage in order to use it in my application.
I successfully did a backup for my database to the internal storage but when I am trying to restore it the following io.exception pops up
java.io.IOException: open failed: ENOENT (No such file or directory)
How can I solve this problem?
However, I tried the follosing existing solutions but they didn't work
Android - java.io.FileNotFoundException,
is it possible backup and RESTORE a database file in android? non root devices,
Restoring SQLite DB file
private void restoreDatabase(Context context) {
String packagename = getPackageName();
File sdcard = Environment.getExternalStorageDirectory();
File data = Environment.getDataDirectory();
try {
if (sdcard.canWrite()) {
String currentDBPath = "//data/"+getPackageName() +"/databases/" + DATABASE_NAME;
String backupDBPath = DATABASE_NAME;
File currentDB = new File(data, currentDBPath);
File backupDB = new File(sdcard, backupDBPath);
currentDB.createNewFile();
if (currentDB.exists()) {
FileChannel src = new FileInputStream(backupDB).getChannel();
FileChannel dst = new FileOutputStream(currentDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast.makeText(getApplicationContext(), "Database Restored successfully", Toast.LENGTH_SHORT).show();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(context, e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(context, e.toString(), Toast.LENGTH_LONG).show();
}
}
Please don't mark this question as duplicate
after exporting your database you can use this function to import the database, I had it testet and it works fine :
private void importDB() {
String appDataPath = getApplicationContext().getApplicationInfo().dataDir;
File dbFolder = new File(appDataPath + "/databases");//Make sure the /databases folder exists
dbFolder.mkdir();//This can be called multiple times.
//EDITED
File dbFilePath = new File(appDataPath + "/databases/"+"yourDataBaseName");
try {
//EDITED
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "YourBackupFolder","yourDataBaseFileName);
FileInputStream inputStream = new FileInputStream(file); //use your database name
OutputStream outputStream = new FileOutputStream(dbFilePath);
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer))>0)
{
outputStream.write(buffer, 0, length);
}
outputStream.flush();
outputStream.close();
inputStream.close();
} catch (IOException e){
//handle
e.printStackTrace();
}
}
my problem is the following:
I have correctly moved the SQlite database on the local SD, but the file is not visible both from the device and the PC via USB connection.
The app does not raise any error.
Here is the method that performs the copy:
private void exportDB(){
DBHelper db = DBHelper.getInstance(this);
String DBName = db.getDBName();
File dbPath = this.getDatabasePath(DBName);
String DBPath = dbPath.getAbsolutePath();
//Toast.makeText(this, "DB Path : " + DBPath , Toast.LENGTH_LONG).show();
File sd = Environment.getExternalStorageDirectory();
File data = Environment.getDataDirectory();
FileChannel source=null;
FileChannel destination=null;
String currentDBPath = DBPath;
String backupDBPath = "Download/"+DBName;
File currentDB = new File(currentDBPath);
File backupDB = new File(sd, backupDBPath);
try {
source = new FileInputStream(currentDB).getChannel();
destination = new FileOutputStream(backupDB).getChannel();
destination.transferFrom(source, 0, source.size());
source.close();
destination.close();
Toast.makeText(this, "DB Exported!", Toast.LENGTH_LONG).show();
} catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}
}
for transferting DB, I think it may achievable in rooted device.
I have a sqlite database in my assets folder. I want to export that file. So I do this:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
//
File direct = new File(Environment.getExternalStorageDirectory()
+ "/Exam Creator");
if (!direct.exists())
{
if (direct.mkdir())
{
// directory is created;
}
}
exportDB();
// importDB();
}
private void exportDB()
{
// TODO Auto-generated method stub
try
{
File sd = Environment.getExternalStorageDirectory();
File data = Environment.getDataDirectory();
if (sd.canWrite())
{
dbopenhelper.copyDataBase();
String currentDBPath = dbopenhelper.DB_PATH
+ dbopenhelper.DATABASE_NAME;
String backupDBPath = "/BackupFolder/Prayers.db";
File currentDB = new File(data, currentDBPath);
File backupDB = new File(sd, backupDBPath);
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast.makeText(getBaseContext(),
backupDB.toString() + "SUCCESS", Toast.LENGTH_LONG)
.show();
}
} catch (Exception e)
{
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG)
.show();
}
}
to get the path of my currentDB, I first copy the database in my project using this method in my DBOpenHelper and by calling it in export method as you can see above.
public static void copyDataBase()
{
try
{
InputStream input = context.getAssets().open(DATABASE_NAME);
FileOutputStream output = new FileOutputStream(DB_PATH
+ DATABASE_NAME);
byte[] data = new byte[1024];
int buffer;
while ((buffer = input.read(data)) != -1)
{
output.write(data, 0, buffer);
}
output.flush();
output.close();
input.close();
} catch (IOException ex)
{
Log.e(LOGTAG, "Error in copying database...");
}
}
but when I run it, I get Filenotfound exception. I debuged it and saw that after this line:
FileChannel src = new FileInputStream(currentDB).getChannel();
it goes to catch block. Does anyone know what is wrong?
Thanks in advance
In my application I have implemented the possibility to export the database by copying the database file on the sdcard.
Without encrypting the file or require special keys to read it I just want to make sure that anyone who picks the file up is able to read db structure or data just by opening it in a sqlite file reader.
How can I implement a light and simple protection for my file?
The following is my code for db exporting.
public void exportDB() {
final String destFolder = "/"+Constants.Files.APP_FOLDER+"/"+Constants.Files.BACKUP_FOLDER;
try {
File myBackupDir = new File(Environment.getExternalStorageDirectory() + destFolder);
if(!myBackupDir.exists() || !myBackupDir.isDirectory()) myBackupDir.mkdirs();
if(myBackupDir.isDirectory()){
File data = Environment.getDataDirectory();
if (Environment.getExternalStorageDirectory().canWrite()) {
final String currentDBPath= "//data//" + Constants.Files.PACKAGE_NAME + "//databases//" + Constants.Files.DB_NAME;
File currentDB = new File(data, currentDBPath);
File backupDB = new File(myBackupDir, Constants.Files.DB_NAME);
if(currentDB.isFile()){
copyFile(new FileInputStream(currentDB), new FileOutputStream(backupDB))
}
}
}
} catch (Exception e) {
Log.e(mTag, "exportDB", e);
}
}
public static void copyFile(FileInputStream fromFile, FileOutputStream toFile) throws IOException {
FileChannel fromChannel = null;
FileChannel toChannel = null;
try {
fromChannel = fromFile.getChannel();
toChannel = toFile.getChannel();
fromChannel.transferTo(0, fromChannel.size(), toChannel);
} finally {
try {
if (fromChannel != null) {
fromChannel.close();
}
} finally {
if (toChannel != null) {
toChannel.close();
}
}
}
}
You can use sqlcipher. It has support for android. You can export it with your existing code since the DB is already encrypted.