2010-01-03 10 views
54

Vorrei aggiungere una funzionalità alla mia app per Android che esegue automaticamente il backup del database SQLite su SD card.Come si esegue il backup di un file di database sulla scheda SD su Android?

Qual è il modo migliore per farlo? Sono disponibili esempi o tutorial?

+1

Nota che se è sulla scheda SD non sarà più privato della tua app. –

+3

@ Mirko N: Lo so, ma le persone vogliono una copia di backup per cose come la reinstallazione, danni al telefono, cose del genere. – CodeFusionMobile

risposta

7

I database SQLite sono file completamente autonomi e sono portatili — è sufficiente copiare l'intero file direttamente sulla scheda SD.

Anche se prima controllerei se una scheda SD è installata nel dispositivo e qual è il suo percorso (usando Environment.getExternalStorageDirectory()).

118

Questo codice funziona per me!

try { 
     File sd = Environment.getExternalStorageDirectory(); 
     File data = Environment.getDataDirectory(); 

     if (sd.canWrite()) { 
      String currentDBPath = "//data//{package name}//databases//{database name}"; 
      String backupDBPath = "{database name}"; 
      File currentDB = new File(data, currentDBPath); 
      File backupDB = new File(sd, backupDBPath); 

      if (currentDB.exists()) { 
       FileChannel src = new FileInputStream(currentDB).getChannel(); 
       FileChannel dst = new FileOutputStream(backupDB).getChannel(); 
       dst.transferFrom(src, 0, src.size()); 
       src.close(); 
       dst.close(); 
      } 
     } 
    } catch (Exception e) { 
    } 

Qualcuno sa se questo funzionerà su telefoni non-root? Ho provato solo su un G1 root.

+18

Posso confermare che funziona su telefoni non rooted. Assicurati di aver aggiunto '' –

+0

currentDB.exists() returnign false .... potrebbe b che il database non sia presente sul sys memoria ma ho successo inserire le righe ... e ottenere il percorso da String currentDBPath = db.getPath(); –

+10

Uso File currentDB = getDatabasePath (DatabaseHelper.DATABASE_NAME); piuttosto che una referenza statica –

1

Non so cosa succede se il telefono è radicata o no, ma si dovrebbe scrivere il file:

/Android/data/{package_name}/files/ 

Ciò funzionerà se è radicata o no.

+2

Il problema con il backup in questa posizione sulla sd-card è che viene eliminato quando l'app viene disinstallata. Potrebbe non essere richiesto per un backup. – ZNS

2

I answered una domanda simile a questa con un metodo che puoi inserire nel tuo SQLiteOpenHelper. È semplice come copiare il file db da una sorta di archivio esterno, nella memoria interna dell'applicazione. C'è anche un codice aggiuntivo che apre e legge il file db per assicurarsi che sia nello stato appropriato per Android per effettuare chiamate al database.

+0

Ho visto il tuo esempio e sembra conciso, come troppo conciso. È difficile per me capire come adattarlo al mio codice. Non so chi sia il codice più efficiente, tutto quello che so è che la logica/codice extra o il codice troppo semplificato rendono più difficile per me capire e adattarmi al mio codice. La maggior parte delle persone crea 4 "FILE" separati, mentre i tuoi creano solo 2 FILE. Perché questo particolare argomento è così confuso? – JamisonMan111

18
try { 
    File sd = Environment.getExternalStorageDirectory(); 
    File data = Environment.getDataDirectory(); 

    if (sd.canWrite()) { 
     String currentDBPath = "//data//"+ packageName +"//databases//"+dbList[0]; 
     String backupDBPath = dbList[0]; 
     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(); 
} 

che funziona al contrario di esempi precedenti in cui il "/" sono "\" sprecato 20 minuti della mia vita capire che fuori, ma ho davvero dovuto vedere che prima. Lo Toast ti dirà dove si trova il file o ti dirà cosa c'è che non va quando non funziona.

+1

iif (sd.canWrite()) non ha funzionato per me. Invece ho usato if (Environment.MEDIA_MOUNTED.equals (stato)) { – Archie

1

È necessario fornire l'autorizzazione android.permission.WRITE_EXTERNAL_STORAGE nell'applicazione. Funziona bene su dispositivi senza radici.

2
public static void BackupDatabase() throws IOException 
{ 
    boolean success =true; 
    File file = null; 
    file = new File(Environment.getExternalStorageDirectory() +"/M.O.L.S_Backup"); 

    if (file.exists()) 
    { 
     success =true; 
    } 
    else 
    { 
     success = file.mkdir(); 
    } 

    if (success) 
    { 
     String inFileName = "/data/data/com.sygic.sdk.demo/databases/MOLS_DB.s3db"; 
     File dbFile = new File(inFileName); 
     FileInputStream fis = new FileInputStream(dbFile); 

     String outFileName = Environment.getExternalStorageDirectory()+"/M.O.L.S_Backup/MOLS_DB.s3db"; 

     // Open the empty db as the output stream 
     OutputStream output = new FileOutputStream(outFileName); 

     // Transfer bytes from the inputfile to the outputfile 
     byte[] buffer = new byte[1024]; 
     int length; 
     while ((length = fis.read(buffer))>0) { 
      output.write(buffer, 0, length); 
     } 

     output.flush(); 
     output.close(); 
     fis.close(); 
    } 
} 
-2

Se il blocco successo mi dà un errore:

String inFileName = context.getDatabasePath(DB-Name); 
File dbFile = new File(inFileName); 
FileInputStream fis = new FileInputStream(dbFile); 
+3

Cosa significa questa prima frase ???? –

+0

Il suo mean get percorso del database – user1154390

0

Potete trovare il nome del database nel database adattatore se siete nuovi a questo.

Nota che puoi farlo anche per SharedPreferences, ma tieni presente di modificare il tuo Context.MODE_PRIVATE in Context.MODE_MULTI_PROCESS.

SharedPreferences_name dovrebbe assomigliare a questa = ExportSP("temp.xml");

String currentPathForSharedPreferences = "/data/"+ context.getPackageName() +"/shared_prefs/"+ SharedPreferences_name; 

Per l'esportazione

exportDB("MyDbName"); 

private void exportDB(String db_name){ 

File sd = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + 
       File.separator + "Your Backup Folder"+ 
       File.separator); 

      boolean success = true; 
      if (!sd.exists()) { 
       success = sd.mkdir(); 
      } 
      if (success) { 

     File data = Environment.getDataDirectory(); 
     FileChannel source=null; 
     FileChannel destination=null; 
     String currentDBPath = "/data/"+ context.getPackageName() +"/databases/"+db_name; 
     String backupDBPath = db_name; 
     File currentDB = new File(data, 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, "Please wait", Toast.LENGTH_SHORT).show(); 
     } catch(IOException e) { 
      e.printStackTrace(); 
     } 
      }} 

Per l'importazione

importDB("MyDbName"); 

private void importDB(String db_name){ 
     File sd = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + 
       File.separator + "Your Backup Folder"+ 
       File.separator); 
     File data = Environment.getDataDirectory(); 
     FileChannel source=null; 
     FileChannel destination=null; 
     String backupDBPath = "/data/"+ context.getPackageName() +"/databases/"+db_name; 
     String currentDBPath = db_name; 
     File currentDB = new File(sd, currentDBPath); 
     File backupDB = new File(data, 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, "Please wait", Toast.LENGTH_SHORT).show(); 
     } catch(IOException e) { 
      e.printStackTrace(); 
     } 
} 
-1
@Override 
protected void onCreate(Bundle savedInstanceState) { 
    try { 
     File sd = Environment.getExternalStorageDirectory(); 
     File data = Environment.getDataDirectory(); 

     if (sd.canWrite()) { 
      String currentDBPath = "//data//"+getPackageName()+"//databases//"+DATABASE_NAME+""; 
      String backupDBPath = "backup.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(), Toast.LENGTH_LONG).show(); 
     } 
    } catch (Exception e) { 
     Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show(); 
    } 
} 
0

@ codice di skeniver funziona per me.Voglio solo aggiungere il seguente:

Usa:

String currentDbPath = getApplicationContext().getDatabasePath("{database name}"); 

che vi darà il vostro percorso di database. È preferibile utilizzare quella invece della codifica della stringa, ad esempio:

String currentDbPath = "//data//{package name}//databases//{database name}"; 
Problemi correlati