1

Currently I am working to implement a SQlite db backup feature in my application with stream. when I backup the database it works and the file has data as I have verified it through "Db browser for SQlite". But when try to restore through FilOuputStream from the database path of my application and InputStream from returned UrI by android SAF(Storage access framework) pointing to external storage where I have put db backup, I get corrupted database file and the connection is also closed.

following are the two methods I am using for this purpose

Taking Backup

   //back db to a URI
public synchronized static boolean backupDb(Context context, Uri uri, String dbNam) throws IOException {
    File dbFile = new File(context.getDatabasePath(dbNam).getPath());
    FileInputStream inFilStream = new FileInputStream(dbFile);
    OutputStream outFilStream = context.getContentResolver().openOutputStream(uri);//new FileOutputStream(backupFile);
    byte[] buffer = new byte[1024];
    int length;
    while ((length = inFilStream.read(buffer)) > 0) {
        outFilStream.write(buffer, 0, length);
    }
    outFilStream.flush();
    outFilStream.close();
    inFilStream.close();
    return true;
}

Restoring Backup

  //restore db from a URI
public static synchronized boolean restoreBackup(Context context, Uri uri, String dbNam) {
    try {
        InputStream inFilStream = context.getContentResolver().openInputStream(uri);
        File dbFile = new File(context.getDatabasePath(dbNam).getPath());
        FileOutputStream outFilStream = new FileOutputStream(dbFile);
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inFilStream.read(buffer)) > 0) {
            outFilStream.write(buffer, 0, length);
            Log.wtf("db", "restoring backup up");
        }
        outFilStream.flush(); 
     // using outFilStream.getFD().sync(); also not working
        outFilStream.close();
        inFilStream.close();
        return true;
    } catch (IOException e) {
        return false;
    }
}

Log

enter image description here

I don't Understand why it is doing so as it is quite weird when I debug and put break points in the restore method it works, could any please help to figure out what is wrong there.

Irfan Ul Haq
  • 1,065
  • 1
  • 11
  • 19
  • is input file and output file has the same size in `backupDb` and in `restoreBackup`. (just File.length()) – ZhenyaM Mar 07 '19 at 08:26
  • Try doing the copy and closing the App. Is the database then valid? The header appears to be correct as the first 15 bytes are *53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00* as per [Database File Format](https://www.sqlite.org/fileformat2.html#database_header)), so it might be that you are encountering a conflict between the replaced and the new database. Alternately, as a test, restore to a different DBname, open that DB and see if you still get the issue, if not then pretty sure that replaced and new conflict (cached data). – MikeT Mar 07 '19 at 20:32
  • Another issue could be if the DB uses WAL is that the -shm and or -wal files have data. More on this [here](https://stackoverflow.com/questions/54051322/database-import-and-export-not-working-in-android-pie/54056779#54056779). – MikeT Mar 07 '19 at 20:39

1 Answers1

0

Looping missed some byte so I had used filechannel like

    public synchronized static boolean saveDbBackup(Context context, Uri uri, String dbNam) throws IOException {
    File dbFile = new File(context.getDatabasePath(dbNam).getPath());
    FileChannel inFilChannel = new FileInputStream(dbFile).getChannel();
    FileChannel outFilChannel = ((FileOutputStream)context.getContentResolver().openOutputStream(uri)).getChannel();//new FileOutputStream(backupFile);
    outFilChannel.transferFrom(inFilChannel,0,inFilChannel.size());
    outFilChannel.close();
    inFilChannel.close();
    return true;
}

public static synchronized boolean restoreDbBackup(Context context, Uri uri, String dbNam) {
    try {
        FileChannel inFileChannel= ((FileInputStream) context.getContentResolver().openInputStream(uri)).getChannel();
        FileChannel outFileChannel= new FileOutputStream(new File(context.getDatabasePath(dbNam).getPath())).getChannel();
        outFileChannel.transferFrom(inFileChannel,0,inFileChannel.size());
        outFilChannel.close();
        inFilChannel.close();
        return true;
    } catch (IOException e) {
        return false;
    }
}
Irfan Ul Haq
  • 1,065
  • 1
  • 11
  • 19