Copy database from assets folder [duplicate]

2019-09-23 01:57发布

问题:

This question already has an answer here:

  • Can't copy SQLite database from assets 4 answers

I am creating a Dictionary application which uses an existing sqlite database. I have placed my database in assets folder and I am using the following code to copy the database when the app is started for first time. (I have borrowed the idea from this post)

DatabaseHelper.java

public class DatabaseHelper {

private static String DB_PATH = "";
private static String DB_NAME = "abc.sqlite";
private SQLiteDatabase myDatabase;
private Context myContext;

public DatabaseHelper(Context context) {

    myContext = context;

    if (android.os.Build.VERSION.SDK_INT >= 17)
        DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
    else
        DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
    Log.d("path", DB_PATH);
}

public void copyDatabase() {

        InputStream myInput;
        OutputStream outStream;
        try {
            myInput = myContext.getAssets().open(DB_NAME);
            String file = DB_PATH + DB_NAME;
            outStream = new FileOutputStream(file);

            byte[] buffer = new byte[1024];
            int length = 0;
            while ((length = myInput.read(buffer)) >= 0) {
                outStream.write(buffer, 0, length);             
            }
            outStream.flush();
            myInput.close();
            outStream.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

And then I call the above copyDatabase() method form my MainActivity. Here is the code.

public class MainActivity extends Activity {
    DatabaseHelper myDbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.layout);
        myDbHelper = new DatabaseHelper(getApplicationContext());
        myDbHelper.copyDatabase();


    }

}

But the problem is that Android does not copy the database. I have used Log tool, and I found out that the while loop never runs. What's the problem in this code. Thanks.

回答1:

Change your while loop as below:

Besides your condition >= greater than or equal to change it to only > Greater than

while ((length = myInput.read(buffer)) > 0) {
            outStream.write(buffer, 0, length);             
        }

Try out the below code which will work for you like charm.

public class DataBaseHelper extends SQLiteOpenHelper {
    private Context mycontext;
    private String DB_PATH; 

    private static String DB_NAME = "abc.sqlite";
    public SQLiteDatabase myDataBase;


    public DataBaseHelper(Context context) throws IOException {
        super(context,DB_NAME,null,1);
        this.mycontext=context;
        boolean dbexist = checkdatabase();
        if (dbexist) {
              opendatabase(); 
        } else {
            System.out.println("Database doesn't exist");
            createdatabase();
        }
    }

    public void createdatabase() throws IOException {
        boolean dbexist = checkdatabase();
        if(!dbexist) {
            this.getReadableDatabase();
            try {
                copydatabase();
            } catch(IOException e) {
                throw new Error("Error copying database");
            }
        }
    }   

    private boolean checkdatabase() {

        boolean checkdb = false;
        try {
            String myPath = DB_PATH + DB_NAME;
            File dbfile = new File(myPath);
            checkdb = dbfile.exists();
        } catch(SQLiteException e) {
            System.out.println("Database doesn't exist");
        }
        return checkdb;
    }

    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 byte to inputfile to 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();
    }

    public void opendatabase() throws SQLException {
        //Open the database
        String mypath = DB_PATH + DB_NAME;
        myDataBase = SQLiteDatabase.openDatabase(mypath, null, SQLiteDatabase.OPEN_READWRITE);
    }

    public synchronized void close() {
        if(myDataBase != null) {
            myDataBase.close();
        }
        super.close();
    }

}

In your MainActivity you just now need to create and instance of your DatabaseHelper class others will managed on it own.

public class MainActivity extends Activity {
    DatabaseHelper myDbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.layout);
        myDbHelper = new DatabaseHelper(MainActivity.this);
      }

}


回答2:

Change this from

while ((length = myInput.read(buffer)) >= 0) {
            outStream.write(buffer, 0, length);             
        }

to

while ((length = myInput.read(buffer)) >0) {
            outStream.write(buffer, 0, length);             
        }

Its a better to copy your database on oncreate() method because in your class you did it. And you have to just call your database class object in your activity and fetch data from it. So first make class named DBConnect

public class DBConnect extends SQLiteOpenHelper {
public int GetCursor;
// ****************** Declare all the global variable
// ****************************//
private Context myContext;
public String DB_PATH = "data/data/com.xyz/databases/"; // path
// of
// your
// datbase
public static String DB_NAME = "xyz.sqlite";// your database name
static String ASSETS_DB_FOLDER = "db";
private SQLiteDatabase db;

public DBConnect(Context context, String db_name) {
    super(context, db_name, null, 2);
    if (db != null && db.isOpen())
        close();

    this.myContext = context;
    DB_NAME = db_name;

    try {
        createDataBase();
        openDataBase();
    } catch (IOException e) {
        // System.out.println("Exception in creation of database : "+
        // e.getMessage());
        e.printStackTrace();
    }

}

public void createDataBase() throws IOException {
    boolean dbExist = checkDataBase();

    if (dbExist) {
        // System.out.println("Database Exist");
    } else {
        this.getReadableDatabase();

        try {
            copyDatabase();
        } catch (IOException e) {
            throw new Error("Error copying database");
        }
    }
}

private void copyDatabase() throws IOException {
    InputStream input = myContext.getAssets().open(DB_NAME);
    String outputFileName = DB_PATH + DB_NAME;
    OutputStream output = new FileOutputStream(outputFileName);

    byte[] buffer = new byte[1024];
    int length;
    while ((length = input.read(buffer)) > 0) {
        output.write(buffer, 0, length);
    }

    // Close the streams
    output.flush();
    output.close();
    input.close();
    // System.out.println(DB_NAME + "Database Copied !");
}

@Override
public void onCreate(SQLiteDatabase db) {

}

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

}

public void openDataBase() throws SQLException {
    // Open the database
    String myPath = DB_PATH + DB_NAME;
    db = SQLiteDatabase.openDatabase(myPath, null,
            SQLiteDatabase.OPEN_READWRITE);
}

public boolean isOpen() {
    if (db != null)
        return db.isOpen();
    return false;
}

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

private boolean checkDataBase() {
    SQLiteDatabase checkDB = null;
    try {
        String myPath = DB_PATH + DB_NAME;
        // System.out.println("My Pathe is:- " + myPath);
        // System.out.println("Open");
        checkDB = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READWRITE);
        // System.out.println("checkDB value:" + checkDB);
        // System.out.println("My Pathe is:- " + myPath);
    } catch (Exception e) {
        // database does't exist yet.
    }

    if (checkDB != null) {
        // System.out.println("Closed");
        checkDB.close();
        // System.out.println("My db is:- " + checkDB.isOpen());
    }

    return checkDB != null ? true : false;
}

public Cursor execCursorQuery(String sql) {
    Cursor cursor = null;
    try {
        cursor = db.rawQuery(sql, null);
        GetCursor = cursor.getCount();
        Log.i("Inside execCursorQuery try", sql);
    } catch (Exception e) {
        Log.i("Inside execCursorQuery exception", e.getMessage());
    }
    return cursor;
}

public void execNonQuery(String sql) {
    try {
        db.execSQL(sql);
        // Log.d("SQL", sql);
    } catch (Exception e) {
        // Log.e("Err", e.getMessage());
    } finally {
        // closeDb();
    }
 }

And in your Activity you should call it by:

public class MainActivity extends Activity {
  DBConnect db;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.layout);
    db= new DBConnect(MainActivity.this,"databasename");
  }

}


回答3:

Used this code for copy Database from assets folder

    public class DataBaseHelper extends SQLiteOpenHelper 
{ 
private static String TAG = "DataBaseHelper"; // Tag just for the LogCat window 
//destination path (location) of our database on device 
private static String DB_PATH = "";  
//private static String DB_NAME ="(students).sqlite";// Database name 
private static String DB_NAME ="virtualDB";
private SQLiteDatabase mDataBase;  
private final Context mContext; 

public DataBaseHelper(Context context)  
{ 
    super(context, DB_NAME, null, 1);// 1? its Database Version 
    DB_PATH = "/data/data/" + context.getPackageName() + "/databases/"; 
    Log.i(TAG, DB_PATH);
    this.mContext = context; 
}    

public void createDataBase() 
{ 
    //If database not exists copy it from the assets 

    boolean mDataBaseExist = checkDataBase(); 
    if(!mDataBaseExist) 
    { 
        this.getReadableDatabase(); 
        this.close(); 
        try  
        { 
            //Copy the database from assests 
            copyDataBase(); 
            Log.e(TAG, "createDatabase database created"); 
        }  
        catch (IOException mIOException)  
        { 
             Log.i(TAG, "createDataBase "+mIOException+"");
        } 
    } 
} 
    //Check that the database exists here: /data/data/your package/databases/Da Name 
    private boolean checkDataBase() 
    { 
        File dbFile = new File(DB_PATH + DB_NAME); 
        //Log.v("dbFile", dbFile + "   "+ dbFile.exists()); 
        return dbFile.exists(); 
    } 

    //Copy the database from assets 
    private void copyDataBase() throws IOException 
    {  try  
    { 
        InputStream mInput = mContext.getAssets().open(DB_NAME); 
        String outFileName = DB_PATH + DB_NAME; 
        OutputStream mOutput = new FileOutputStream(outFileName); 
        byte[] mBuffer = new byte[1024]; 
        int mLength; 
        while ((mLength = mInput.read(mBuffer))>0) 
        { 
            mOutput.write(mBuffer, 0, mLength); 
        } 
        mOutput.flush(); 
        mOutput.close(); 
        mInput.close(); 
    }  
    catch (IOException mIOException)  
    { Log.i(TAG,"copyDataBase "+ mIOException+"");

    } 
    } 

    //Open the database, so we can query it 
    public boolean openDataBase() throws SQLException 
    { 
        String mPath = DB_PATH + DB_NAME; 
        //Log.v("mPath", mPath); 
        mDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.CREATE_IF_NECESSARY); 
        //mDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS); 
        return mDataBase != null; 
    } 

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

    @Override
    public void onCreate(SQLiteDatabase arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // TODO Auto-generated method stub

    } 

} 

This code working fine for me I hope it help you



回答4:

Please check this supporting project to handle sqlite db from asset https://github.com/jgilfelt/android-sqlite-asset-helper hope this will help you.