2015-07-12 17 views
10

Sto cercando di esportare i dati SQLite su scheda SD in Android come file CSV su una directory.Esportazione di database SQLite in file csv in Android

così ho provato questo metodo qui sotto e apparentemente si vede solo il testo stampato:

PRIMO tabella del database
data, punto, IMPORTO, VALUTA

Nel mio DBHelper.java Ho definito la funzione come segue:

public boolean exportDatabase() { 
     DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()); 

     /**First of all we check if the external storage of the device is available for writing. 
     * Remember that the external storage is not necessarily the sd card. Very often it is 
     * the device storage. 
     */ 
     String state = Environment.getExternalStorageState(); 
     if (!Environment.MEDIA_MOUNTED.equals(state)) { 
      return false; 
     } 
     else { 
      //We use the Download directory for saving our .csv file. 
      File exportDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); 
      if (!exportDir.exists()) 
      { 
       exportDir.mkdirs(); 
      } 

      File file; 
      PrintWriter printWriter = null; 
      try 
      { 
       file = new File(exportDir, "MyCSVFile.csv"); 
       file.createNewFile(); 
       printWriter = new PrintWriter(new FileWriter(file)); 

       /**This is our database connector class that reads the data from the database. 
       * The code of this class is omitted for brevity. 
       */ 
       SQLiteDatabase db = this.getReadableDatabase(); //open the database for reading 

       /**Let's read the first table of the database. 
       * getFirstTable() is a method in our DBCOurDatabaseConnector class which retrieves a Cursor 
       * containing all records of the table (all fields). 
       * The code of this class is omitted for brevity. 
       */ 
       Cursor curCSV = db.rawQuery("select * from contacts", null); 
       //Write the name of the table and the name of the columns (comma separated values) in the .csv file. 
       printWriter.println("FIRST TABLE OF THE DATABASE"); 
       printWriter.println("DATE,ITEM,AMOUNT,CURRENCY"); 
       while(curCSV.moveToNext()) 
       { 
        Long date = curCSV.getLong(curCSV.getColumnIndex("date")); 
        String title = curCSV.getString(curCSV.getColumnIndex("title")); 
        Float amount = curCSV.getFloat(curCSV.getColumnIndex("amount")); 
        String description = curCSV.getString(curCSV.getColumnIndex("description")); 

        /**Create the line to write in the .csv file. 
        * We need a String where values are comma separated. 
        * The field date (Long) is formatted in a readable text. The amount field 
        * is converted into String. 
        */ 
        String record = df.format(new Date(date)) + "," + title + "," + amount + "," + description; 
        printWriter.println(record); //write the record in the .csv file 
       } 

       curCSV.close(); 
       db.close(); 
      } 

      catch(Exception exc) { 
       //if there are any exceptions, return false 
       return false; 
      } 
      finally { 
       if(printWriter != null) printWriter.close(); 
      } 

      //If there are no errors, return true. 
      return true; 
     } 
    } 
} 

E le mie colonne sono:

public static final String DATABASE_NAME = "MyDBName.db"; 
public static final String CONTACTS_TABLE_NAME = "contacts"; 
public static final String CONTACTS_COLUMN_ID = "id"; 
public static final String CONTACTS_COLUMN_TITLE = "title"; 
public static final String CONTACTS_COLUMN_AMOUNT = "amount"; 
public static final String CONTACTS_COLUMN_DESC = "description"; 

Fatemi sapere se avete bisogno di più codice.

+0

cosa vuoi? stai ricevendo qualche errore. – RajSharma

+1

'// Scrivi il nome della tabella e il nome delle colonne (valori separati da virgola) nel file .csv. Quindi, non è più un file CSV valido, se aggiungi il nome della tabella. La prima riga in un file CSV valido è una riga di intestazione con i nomi di colonna o è solo la prima riga di dati. –

+0

Per quanto riguarda il tuo problema ... sembra che non ci siano dati nella tabella. –

risposta

21

Grazie per i vostri suggerimenti ragazzi che mi hanno portato a questa risposta:

private void exportDB() { 
 

 
     File dbFile=getDatabasePath("MyDBName.db"); 
 
     DBHelper dbhelper = new DBHelper(getApplicationContext()); 
 
     File exportDir = new File(Environment.getExternalStorageDirectory(), ""); 
 
     if (!exportDir.exists()) 
 
     { 
 
      exportDir.mkdirs(); 
 
     } 
 

 
     File file = new File(exportDir, "csvname.csv"); 
 
     try 
 
     { 
 
      file.createNewFile(); 
 
      CSVWriter csvWrite = new CSVWriter(new FileWriter(file)); 
 
      SQLiteDatabase db = dbhelper.getReadableDatabase(); 
 
      Cursor curCSV = db.rawQuery("SELECT * FROM contacts",null); 
 
      csvWrite.writeNext(curCSV.getColumnNames()); 
 
      while(curCSV.moveToNext()) 
 
      { 
 
       //Which column you want to exprort 
 
       String arrStr[] ={curCSV.getString(0),curCSV.getString(1), curCSV.getString(2)}; 
 
       csvWrite.writeNext(arrStr); 
 
      } 
 
      csvWrite.close(); 
 
      curCSV.close(); 
 
     } 
 
     catch(Exception sqlEx) 
 
     { 
 
      Log.e("MainActivity", sqlEx.getMessage(), sqlEx); 
 
     }

+0

Non è chiaro dove ottenere 'getDatabasePath',' DBHelper', 'CSVWriter' e altre parti di questo codice. – zygimantus

+0

'metodo getDatabasePath()' trova il percorso del percorso del database, 'DBHelper' è la mia classe di gestore sqlite che estende' sqliteOpenHelper', 'CSVWriter' è la funzione CSV. Il codice funziona direttamente senza troppa fretta. –

+0

Un peccato che tu non stia condividendo queste lezioni qui. Potrebbero essere utili per gli altri. – leoneboaventura

1

Prima di tutto rimuovere questa riga per avere un documento in formato csv valido.

printWriter.println("FIRST TABLE OF THE DATABASE"); 

In secondo luogo, assicurarsi di avere i dati nella tabella e verificare se la query in realtà restituisce nulla per il debug.

1

Nel caso qualcuno inciampa ancora su questa domanda, mi post la mia soluzione, che è leggermente più generale di quello accettato Dovresti essere in grado di esportare tutte le tabelle in un database SQLite quasi copiando le due classi seguenti. Solo altre modifiche necessarie dovrebbero essere correlate al contesto dell'applicazione e all'importazione di CSV aperto.

Alcune parti sono praticamente copia da altri thread di stackoverflow, ma non sono riuscito a trovarle.

esportatore Sqlite:

import android.database.Cursor; 
import android.database.sqlite.SQLiteDatabase; 
import android.util.Log; 

import com.opencsv.CSVWriter; 

import java.io.File; 
import java.io.FileWriter; 
import java.io.IOException; 
import java.text.SimpleDateFormat; 
import java.util.ArrayList; 
import java.util.Date; 
import java.util.List; 


/** 
* Can export an sqlite databse into a csv file. 
* 
* The file has on the top dbVersion and on top of each table data the name of the table 
* 
* Inspired by 
* https://stackoverflow.com/questions/31367270/exporting-sqlite-database-to-csv-file-in-android 
* and some other SO threads as well. 
* 
*/ 
public class SqliteExporter { 
    private static final String TAG = SqliteExporter.class.getSimpleName(); 

    public static final String DB_BACKUP_DB_VERSION_KEY = "dbVersion"; 
    public static final String DB_BACKUP_TABLE_NAME = "table"; 

    public static String export(SQLiteDatabase db) throws IOException{ 
     if(!FileUtils.isExternalStorageWritable()){ 
      throw new IOException("Cannot write to external storage"); 
     } 
     File backupDir = FileUtils.createDirIfNotExist(FileUtils.getAppDir() + "/backup"); 
     String fileName = createBackupFileName(); 
     File backupFile = new File(backupDir, fileName); 
     boolean success = backupFile.createNewFile(); 
     if(!success){ 
      throw new IOException("Failed to create the backup file"); 
     } 
     List<String> tables = getTablesOnDataBase(db); 
     Log.d(TAG, "Started to fill the backup file in " + backupFile.getAbsolutePath()); 
     long starTime = System.currentTimeMillis(); 
     writeCsv(backupFile, db, tables); 
     long endTime = System.currentTimeMillis(); 
     Log.d(TAG, "Creating backup took " + (endTime - starTime) + "ms."); 

     return backupFile.getAbsolutePath(); 
    } 

    private static String createBackupFileName(){ 
     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HHmm"); 
     return "db_backup_" + sdf.format(new Date()) + ".csv"; 
    } 

    /** 
    * Get all the table names we have in db 
    * 
    * @param db 
    * @return 
    */ 
    public static List<String> getTablesOnDataBase(SQLiteDatabase db){ 
     Cursor c = null; 
     List<String> tables = new ArrayList<>(); 
     try{ 
      c = db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null); 
      if (c.moveToFirst()) { 
       while (!c.isAfterLast()) { 
        tables.add(c.getString(0)); 
        c.moveToNext(); 
       } 
      } 
     } 
     catch(Exception throwable){ 
      Log.e(TAG, "Could not get the table names from db", throwable); 
     } 
     finally{ 
      if(c!=null) 
       c.close(); 
     } 
     return tables; 
    } 

    private static void writeCsv(File backupFile, SQLiteDatabase db, List<String> tables){ 
     CSVWriter csvWrite = null; 
     Cursor curCSV = null; 
     try { 
      csvWrite = new CSVWriter(new FileWriter(backupFile)); 
      writeSingleValue(csvWrite, DB_BACKUP_DB_VERSION_KEY + "=" + db.getVersion()); 
      for(String table: tables){ 
       writeSingleValue(csvWrite, DB_BACKUP_TABLE_NAME + "=" + table); 
       curCSV = db.rawQuery("SELECT * FROM " + table,null); 
       csvWrite.writeNext(curCSV.getColumnNames()); 
       while(curCSV.moveToNext()) { 
        int columns = curCSV.getColumnCount(); 
        String[] columnArr = new String[columns]; 
        for(int i = 0; i < columns; i++){ 
         columnArr[i] = curCSV.getString(i); 
        } 
        csvWrite.writeNext(columnArr); 
       } 
      } 
     } 
     catch(Exception sqlEx) { 
      Log.e(TAG, sqlEx.getMessage(), sqlEx); 
     }finally { 
      if(csvWrite != null){ 
       try { 
        csvWrite.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
      if(curCSV != null){ 
       curCSV.close(); 
      } 
     } 
    } 

    private static void writeSingleValue(CSVWriter writer, String value){ 
     writer.writeNext(new String[]{value}); 
    } 
} 

fileutils:

public class FileUtils { 

    public static String getAppDir(){ 
     return App.getContext().getExternalFilesDir(null) + "/" + App.getContext().getString(R.string.app_name); 
    } 

    public static File createDirIfNotExist(String path){ 
     File dir = new File(path); 
     if(!dir.exists()){ 
      dir.mkdir(); 
     } 
     return dir; 
    } 

    /* Checks if external storage is available for read and write */ 
    public static boolean isExternalStorageWritable() { 
     String state = Environment.getExternalStorageState(); 
     return Environment.MEDIA_MOUNTED.equals(state); 
    } 

    /* Checks if external storage is available to at least read */ 
    public static boolean isExternalStorageReadable() { 
     String state = Environment.getExternalStorageState(); 
     return Environment.MEDIA_MOUNTED.equals(state) || 
       Environment.MEDIA_MOUNTED_READ_ONLY.equals(state); 
    } 
} 

In aggiunta a queste due classi, si sia bisogno di passare contesto fileutils, o hanno altri mezzi di ottenere il contesto. Nel codice sopra l'App è solo una classe che estende l'applicazione per un facile accesso al contesto.

Ricorda inoltre di aggiungere Opencsv a Gradle, vale a dire

compile group: 'com.opencsv', name: 'opencsv', version: '4.1' 

Poi basta chiamare il metodo di esportazione della classe esportatore SQLite.

+0

Come chiamare questo metodo da MainActivity ? – user2872856

+0

Puoi chiamarlo con 'SqliteExporter.export (db)' dove db è l'oggetto SQLiteDatabase, che puoi ottenere ad esempio da sqliteOpenHelper con getReadableDatabase() – Pete

+0

Probabilmente vuoi chiamare il metodo di esportazione da un thread in background, dato che può richiedere un po 'di tempo per esportare il database. Per questo potresti voler creare un intentService o qualcos'altro che non blocchi il thread ui. – Pete