将我自己的SQLite DB从Asset文件夹复制到

时间:2010-12-13 23:06:19

标签: android sqlite

我不明白为什么我无法将我的db文件(abic_)复制到应用程序目录(“/ data / data /”+ context.getPackageName()+“/ databases”)

这是我的DataBaseHelper类:


import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;import java.io.OutputStream;

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;


public class DataBaseHelper extends SQLiteOpenHelper{

    //The Android's default system path of your application database.
    private String DB_PATH;

    private static String DB_NAME = "abic_";
    private static final Integer DB_VERSION = 1;

    private SQLiteDatabase mydb; 

    private final Context myContext;

    /**
     * Constructor
     * Takes and keeps a reference of the passed context in order to access to the application assets and resources.
     * @param context
     */
    public DataBaseHelper(Context context) {

        super(context, DB_NAME, null, DB_VERSION);
        this.myContext = context;
        DB_PATH = "/data/data/" + context.getPackageName() + "/databases";
    }   

    @Override
    public void onCreate(SQLiteDatabase db) {;
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }

public void apriDatabase() throws SQLException {
    try {
            String percorso = DB_PATH + DB_NAME;
            mydb = SQLiteDatabase.openDatabase(percorso, null, SQLiteDatabase.OPEN_READONLY);
    } catch (Exception e) {
            e.printStackTrace();
    }
}

public void createDataBase() throws IOException{
    boolean dbExist = checkDataBase();
    if(dbExist){
            //do nothing - database already exist
    }else{
            //By calling this method and empty database will be created into the default system path
           //of your application so we are gonna be able to overwrite that database with our database.
            this.getReadableDatabase();
            try {
                    copyDataBase();
            } catch (IOException e) {
                    e.printStackTrace();
            }
    }
}

private void copyDataBase() throws IOException{
    //Open your local db as the input stream
    InputStream myInput = myContext.getAssets().open(DB_NAME);
    // Path to the just created empty db
    String outFileName = DB_PATH + DB_NAME;

    // if the path doesn't exist first, create it
    File f = new File(outFileName);
    if (!f.exists()){
            f.mkdir();
            f.createNewFile();
    }

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

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

    //Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();

}

private boolean checkDataBase(){

    SQLiteDatabase checkDB = null;

    try{
            String myPath = DB_PATH + DB_NAME;
            checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);

    }catch(SQLiteException e){

            //database does't exist yet.

    }

    if(checkDB != null){

            checkDB.close();

    }

    return checkDB != null ? true : false;
} 

@Override
    public synchronized void close() {
        if(mydb != null)
            mydb.close();
        super.close();
    }

}

这是使用此类的列表视图:

  import android.app.ListActivity;
import android.content.Intent;
import android.database.Cursor; 
import android.database.sqlite.SQLiteDatabase; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.EditText; 
import android.widget.ListAdapter; 
import android.widget.ListView; 
import android.widget.SimpleCursorAdapter; 

public class abicabList extends ListActivity { 

        protected EditText searchText; 
        protected SQLiteDatabase mydb; 
        protected Cursor cursor; 
        protected ListAdapter adapter; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
        mydb = (new DataBaseHelper(this)).getWritableDatabase(); 
        searchText = (EditText) findViewById (R.id.searchText); 
    } 

    public void search(View view) { 

     String text = searchText.getText().toString();
     String cap = "CAP";
     // || is the concatenation operation in SQLite 
      if (text.length()14) {      
 cursor = mydb.rawQuery("SELECT _id, ABI, BANCA, CAB, CAP, Filiale, City FROM abicab WHERE ABI || CAB LIKE ? LIMIT 30",  
          new String[]{"%" + searchText.getText().toString().substring(6,10) + "%" + searchText.getText().toString().substring(11,15) + "%"});     
     adapter = new SimpleCursorAdapter( 
                                this,  
                                R.layout.abicab_list_item,  
                                cursor,  
                                new String[] {"BANCA", "Filiale", "City", "CAP"},  
              new int[] {R.id.BANCA, R.id.Filiale, R.id.City ,R.id.CAP});
      setListAdapter(adapter);
    } 

   }  

因此,当我运行应用程序时,db在文件夹中创建,但它不包含我在资产文件夹中的数据库中的表(参见图片[1]:http://i.stack.imgur.com/AaFj8.jpg)。 在此先感谢您的帮助。

4 个答案:

答案 0 :(得分:3)

我已经解决了这个问题。

1)我使用了Almanac 0.0.17(开源项目)中使用的AlmanacSQLiteDatabaseAdapter.java类,您可以在这里找到: link。您可以满足您的需求(在我的情况下,我已经重命名为DatabaseHelper);

2)这是使用Helper的类(它是一个listview,它在EditText中执行sql rawquery读取字符串 - 这是本教程“coenraets.org/blog/android-samples/androidtutorial/”的安排:

public class MiaList extends Activity { 

        protected EditText searchText; 
        protected SQLiteDatabase db; 
        protected Cursor cursor; 
        protected ListAdapter ladapter; 
        protected ListView miaList; 
        private static final String DATABASE_NAME = "miodb.jpg";
/*
L'ESTENSIONE JPG (o mp3, mov) questo perchè android ha il limite di 1 mb per i file di testo 
o simili nella asset, mentre NON HA limiti per i file multimediali! Nel mio caso si tratta di 4mb
*/

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 

//qui sotto richiamo la classe DatabaseHelper

        DatabaseHelper dbAdapter = DatabaseHelper.getInstance(this, DATABASE_NAME);
        /*note di Vytek*/
        // OK Dovrei usare aSQLiteDatabaseAdapter.getDatabase(); ma questo crea
        // problemi nella fase di OnPause quando premo Back cosi' invece non
        // ottengo errori
        // e viene fatta la normale copia del DB (13/8/2010 23.18)
        // db = aSQLiteDatabaseAdapter.getWritableDatabase();
        // Per ovviare a questo problema controllo se e' la prima volta che
        // chiamo applicazione
        if (getFirstRun()) {
                db = dbAdapter.getDatabase();
                setRunned();
        } else {
                db = dbAdapter.getWritableDatabase();
        }

        searchText = (EditText) findViewById (R.id.searchText); 
        miaList = (ListView) findViewById (R.id.list); 
    } 


    private void setRunned() {
                // TODO Auto-generated method stub

        }

        private boolean getFirstRun() {
                // TODO Auto-generated method stub
                return false;
        }

        public void search(View view) { 

        String text = searchText.getText().toString();
        // || è l'operatore "concatena" in SQLite 
         if (text.length()<15){
                    cursor = db.rawQuery("SELECT *FROM miatable WHERE AAA || ' ' || BBB || ' ' || CCC LIKE ? LIMIT 30",  
                            new String[]{"%" + searchText.getText().toString() + "%"}); 
                                ladapter = new SimpleCursorAdapter( 
                                                this,  
                                                R.layout.mialist_list_item,  
                                                cursor,  
                                                new String[] {"_id", "AAA", "BBB", "CCC"},  
                                                new int[] {R.id._id, R.id.AAA, R.id.BBB, R.id.CCC}); 
                                miaList.setAdapter(ladapter); 
                                //istruzione da eseguire
                }
         else {         
                   cursor = db.rawQuery("SELECT * FROM miatable WHERE AAA || BBB LIKE ? LIMIT 30",  
                           new String[]{"%" + searchText.getText().toString().substring(6,10) + "%" + searchText.getText().toString().substring(11,15) + "%"});         
                                ladapter = new SimpleCursorAdapter( 
                                                this,  
                                                R.layout.mialist_list_item,  
                                                cursor,  
                                                new String[] {"_id", "AAA", "BBB", "CCC"},  
                                                new int[] {R.id._id, R.id.AAA, R.id.BBB, R.id.CCC}); 
                                miaList.setAdapter(ladapter); 
                                //istruzione da eseguire
                  } 


        }

}

当然,SQLite DB“miodb.jpg”必须位于eclipse工作区的资产文件夹中。

<强> PS 我使用了jpg扩展名,因为资产文件夹对db或txt或xml扩展名有1Mb限制。

答案 1 :(得分:2)

您使用的是仿真器还是设备?

我做了同样的程序但是我将数据库复制到SD卡中,因为模拟器的空间大小有限,数据库的大小是多少?


用这个替换你的副本方法,让我知道,因为除了复制方法,我找不到任何奇怪的东西,祝你好运。

private void copyDataBase() throws IOException{

    //Open your local db as the input stream
    InputStream myInput = myContext.getAssets().open(DB_NAME);

    // Path to the just created empty db
    String outFileName = DB_PATH + DB_NAME;

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

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

    //Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();

}

答案 2 :(得分:2)

首先确保将android.permission.WRITE_EXTERNAL_STORAGE权限添加到清单文件中。 在我的一个应用程序中,我使用下面的类,它完美地工作。试试这个,让我知道它是否有效。

public class ImpotDatabaseFileTask extends AsyncTask<String, Void, Boolean> {
ProgressDialog dialog;
private Context con;
boolean success = false;

public ImpotDatabaseFileTask(Context con) {
    this.con = con;
    dialog = new ProgressDialog(con);
    this.dialog.setMessage("Importing database...");
    execute(null);
}

@Override
protected Boolean doInBackground(String... params) {
    try {
        OutputStream myOutput;
        File destination = new File(Environment.getDataDirectory()
                + "//data//<package name>//databases//database_name.db");

        // Set the folder on the SDcard
        File dbFile = new File(Environment.getExternalStorageDirectory(),
                "//<custom folder>//<database_name>.db");
        if (dbFile.exists()) {
            copyFile(dbFile, destination);
            success = true;
        }

    } catch (FileNotFoundException e) {
        // Toast.makeText(Settings.this,
        // "Restore unsuccessful! File not found! Directory does not exist?",
        // Toast.LENGTH_LONG).show();

        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        Toast.makeText(con, "Restore unsuccessful!", Toast.LENGTH_SHORT)
                .show();

        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}

void copyFile(File src, File dst) throws IOException {
    FileChannel inChannel = new FileInputStream(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();
    }
}

@Override
protected void onPostExecute(Boolean result) {
    if (this.dialog.isShowing()) {
        this.dialog.dismiss();
    }
    if (success) {
        Toast.makeText(con, "Restore successful!", Toast.LENGTH_SHORT)
                .show();
    } else {
        Toast.makeText(con, "Restore failed", Toast.LENGTH_SHORT).show();
    }
    super.onPostExecute(result);
}

}

答案 3 :(得分:0)

以下是我使用的简单方便的代码:

public class DataBaseImportHelper {
    private DataBaseImportHelper() {}; // Avoid instantiation

/**
 * Creates a empty database on the system and rewrites it with your own database.
 */
public static boolean importDataBase(Context context) {
    InputStream myInput = null;
    OutputStream myOutput = null;
    try {
        // Open local db from assets as the input stream
        myInput = context.getAssets().open(DATABASE_NAME);
        createEmptyDatabase(context); // See this method below
        // Open the empty db as the output stream
        myOutput = new FileOutputStream(getDatabaseFile(context));

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

        // Close the streams
        myOutput.flush();
        myInput.close();
        myOutput.close();
        return true;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return false;
}

/**
 * Check if the database already exists.
 * @return true if it exists, false if it doesn't
 */
public static boolean isDatabaseExists(Context context) {
    return getDatabaseFile(context).exists();
}

private static File getDatabaseFile(Context context) {
    return context.getDatabasePath(DatabaseHelper.DATABASE_NAME);
}

/**
 * Create an empty database into the default application database
 * folder.So we are gonna be able to overwrite that database with our database
 */
private static void createEmptyDatabase(Context context) {
            // use anonimous helper to create empty database
    new SQLiteOpenHelper(context, DatabaseHelper.DATABASE_NAME, null, 1) {
                    // Methods are empty. We don`t need to override them
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
        }
    }.getReadableDatabase().close();
}

}

在代码中使用:

if(!DataBaseImportHelper.isDatabaseExists(this)){
    if (!DataBaseImportHelper.importDataBase(this)){
            throw new IllegalStateException("Database doesn`t exist and hasn`t been copied!");
    }
}