Sqlcipher __ CREATE TABLE android_metadata失败 [英] Sqlcipher __ CREATE TABLE android_metadata failed

查看:532
本文介绍了Sqlcipher __ CREATE TABLE android_metadata失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我的Andr​​oid应用程序附加现有sqlcipher数据库(加密),但在我的目录拷贝后不能使用打开SQLiteDatabase.openDatabase(......)

我试过code在正常sqlite的,它工作正常,但是当我用sqlcipher API我得到这个错误信息

  // CREATE TABLE android_metadata失败
 //失败的setLocale()施工时,关闭数据库
 // net.sqlcipher.database.SQLiteException:文件被加密或不是一个数据库
 

我用里面SQLiteOpenHelper类以下code:

 如果(!dbExist1)
      {

            this.getWritableDatabase(密码);
            this.openDatabase();
            尝试
            {
                  this.close();
                  copyDataBase();
            }
            赶上(IOException异常E)
            {

                  抛出新的错误(错误复制数据库);
            }
      }


        公共SQLiteDatabase的openDatabase()抛出的SQLException {
    字符串DBPATH = DATABASE_PATH + DATABASE_NAME;

    MyDatabase的= SQLiteDatabase.openDatabase(DBPATH,密码为空,
            SQLiteDatabase.NO_LOCALIZED_COLLATORS);
    返回MyDatabase的;
}
 

和我用下面的code活性类中:

  SQLiteDatabase.loadLibs(本);
 DataBaseHelper myDbHelper;
      myDbHelper =新DataBaseHelper(本);
  SQLiteDatabase DB = myDbHelper.openDatabase();
 

我试图用该解决方案但还是同样的错误

  

块引用

解决方案

非常感谢尼克·帕克,其实我用从样品code片段,我创建了一个新的类重presenting的复制SqlCipherAssestHelper加密从资产数据库,以在设备中的另一个位置,并宣读了新的复制/写入使用该数据库的样本中1x.db的这里

这是助手CALSS:

 包com.example.readdbfromas;

进口的java.io.File;
进口java.io.FileOutputStream中;
进口java.io.IOException异常;
进口的java.io.InputStream;
进口java.io.OutputStream中;

进口net.sqlcipher.SQLException;
进口net.sqlcipher.database.SQLiteDatabase;
进口net.sqlcipher.database.SQLiteDatabaseHook;
进口net.sqlcipher.database.SQLiteException;
进口net.sqlcipher.database.SQLiteOpenHelper;
进口android.content.Context;
进口android.os.Environment;
进口android.util.Log;

公共类DataBaseHelper扩展SQLiteOpenHelper {

    私有静态最后弦乐DATABASE_NAME =1x.db; //加密数据库
    私有静态最后弦乐SUB_DATABASE_FOLDER =/ DatabaseCipher /; //子文件夹数据库位置
    公共静态字符串DATABASE_PATH;
    公共静态最终诠释DATABASE_VERSION = 1;
    私人SQLiteDatabase MyDatabase的;
    私人最终上下文的背景下;
    私人字符串密码=;
    私人字符串FULL_DB_Path;

    公共DataBaseHelper(上下文的背景下){

        超(背景下,DATABASE_NAME,空,DATABASE_VERSION);

        DATABASE_PATH = Environment.getExternalStorageDirectory()
                .getAbsolutePath()的toString()
                + SUB_DATABASE_FOLDER; //获取设备根目录下复制数据的基础上就可以了

        this.context =背景;
        SQLiteDatabase.loadLibs(context.getApplicationContext()); //负荷SqlCipher库

        FULL_DB_Path = DATABASE_PATH + DATABASE_NAME; //完整的数据库路径
    }

    公共SQLiteDatabase开(字符串密码){
        this.password =密码;

        如果(!checkDataBase()){//如果数据库不存在
            copyDataBase();
        }

        MyDatabase的= getExistDataBaseFile();

        返回MyDatabase的;
    }

    私人SQLiteDatabase getExistDataBaseFile(){//这个函数打开一个存在的数据库

        SQLiteDatabaseHook挂钩=新SQLiteDatabaseHook(){
            公共无效pre键(SQLiteDatabase数据库){
            }

            公共无效postKey(SQLiteDatabase数据库){
                database.rawExecSQL(杂cipher_migrate;);

            }
        };
        返回SQLiteDatabase.openOrCreateDatabase(FULL_DB_Path,密码,
                空,钩);

    }


    私人布尔checkDataBase(){//检查数据库文件已经存在或不
        布尔CHECKDB = FALSE;
        尝试 {
            文件DBFILE =新的文件(FULL_DB_Path);
            CHECKDB = dbfile.exists();
        }赶上(SQLiteException E){
        }
        返回CHECKDB;
    }


    公共无效db_delete(){//删除数据库
        档案文件=新的文件(FULL_DB_Path);
        如果(file.exists()){
            file.delete();
            的System.out.println(删除数据库文件。);
        }
    }

    私人无效copyDataBase(){//做一个子文件夹数据库位置和数据库复制
        尝试 {
            文件FOFO =新的文件(DATABASE_PATH);
            fofo.mkdirs();
            extractAssetToDatabaseDirectory(DATABASE_NAME);
        }赶上(IOException异常E){
            e.printStackTrace();
        }

    }

    市民同步无效closeDataBase()抛出的SQLException {
        如果(MyDatabase的!= NULL)
            myDataBase.close();
        super.close();
    }

    公共无效extractAssetToDatabaseDirectory(字符串文件名)
            抛出IOException异常{//复制数据库

        INT长;
        InputStream的sourceDatabase = context.getAssets()打开(文件名)。
        文件的DestinationPath =新的文件(FULL_DB_Path);
        OutputStream的目标=新的FileOutputStream(的DestinationPath);

        byte []的缓冲区=新的字节[4096];
        而((长度= sourceDatabase.read(缓冲液))大于0){
            destination.write(缓冲液,0,长度);
        }
        sourceDatabase.close();
        destination.flush();
        destination.close();
    }

    公共无效onUpgrade(SQLiteDatabase分贝,INT oldVersion,诠释静态网页){
    }

    公共无效的onCreate(SQLiteDatabase DB){
    }

    公共布尔的ChangePassword(字符串NEWPASSWORD){//数据库必须
                                                        //前开
                                                        //改变密码

        尝试 {
            如果(MyDatabase的空=&安培;!&安培; myDataBase.isOpen()){

                myDataBase.rawExecSQL(立即开始交易;);
                myDataBase.rawExecSQL(杂密钥更新='+新密码+;);

                this.close();
                myDataBase.close();

                返回true;

            } 其他 {

                Log.e(布尔的ChangePassword(),
                        更改密码错误:数据库为空或不开!);
                返回false;
            }
        }赶上(例外五){

            Log.e(布尔的ChangePassword(),
                    更改密码错误:ExecSQL错误!);
            返回false;

        }

    }

}
 

和内部活动这一code:

  SQLiteDatabase分贝;
DataBaseHelper myDbHelper =新DataBaseHelper(MainActivity.this);
       DB = myDbHelper.open(测试);


  光标光标= db.rawQuery(SELECT * FROM T1,NULL);
 

I'm trying to attach a existing sqlcipher database(encrypted) in my android application but after copying it in my directory it cannot be opened using "SQLiteDatabase.openDatabase(...)"

I tried the code in normal sqlite and it works correctly but when I used sqlcipher API i got this error message

 //CREATE TABLE android_metadata failed
 //Failed to setLocale() when constructing, closing the database
 // net.sqlcipher.database.SQLiteException: file is encrypted or is not a database

I used the following code inside SQLiteOpenHelper Class :

      if(!dbExist1)
      {

            this.getWritableDatabase(password);
            this.openDatabase();
            try
            {
                  this.close();    
                  copyDataBase();
            }
            catch (IOException e)
            {

                  throw new Error("Error copying database");
            }
      }


        public SQLiteDatabase openDatabase() throws SQLException {
    String DBPath = DATABASE_PATH + DATABASE_NAME;

    myDataBase = SQLiteDatabase.openDatabase(DBPath, password, null,
            SQLiteDatabase.NO_LOCALIZED_COLLATORS);
    return myDataBase;
}

And I used the following code inside Activity Class :

  SQLiteDatabase.loadLibs(this);
 DataBaseHelper myDbHelper ;
      myDbHelper = new DataBaseHelper(this);
  SQLiteDatabase db=myDbHelper.openDatabase();

i tried to use this solution but still same error

Blockquote

解决方案

Thanks a lot Nick Parker ,actually i used a code snippet from your sample and i created a new class representing SqlCipherAssestHelper that copy the encrypted DataBase from assets to another location in the device and read/write from the new copy using the database in the sample "1x.db" here

this is the Helper Calss:

package com.example.readdbfromas;

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

import net.sqlcipher.SQLException;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteDatabaseHook;
import net.sqlcipher.database.SQLiteException;
import net.sqlcipher.database.SQLiteOpenHelper;
import android.content.Context;
import android.os.Environment;
import android.util.Log;

public class DataBaseHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "1x.db";// Encrypted Database
    private static final String SUB_DATABASE_FOLDER = "/DatabaseCipher/";// a sub folder for database location
    public static String DATABASE_PATH;
    public static final int DATABASE_VERSION = 1;
    private SQLiteDatabase myDataBase;
    private final Context context;
    private String password = "";
    private String FULL_DB_Path;

    public DataBaseHelper(Context context) {

        super(context, DATABASE_NAME, null, DATABASE_VERSION);

        DATABASE_PATH = Environment.getExternalStorageDirectory()
                .getAbsolutePath().toString()
                + SUB_DATABASE_FOLDER;//get the device root Directory to copy data base on it 

        this.context = context;
        SQLiteDatabase.loadLibs(context.getApplicationContext());//load SqlCipher libraries

        FULL_DB_Path = DATABASE_PATH + DATABASE_NAME;//full database path
    }

    public SQLiteDatabase open(String password) {
        this.password = password;

        if (!checkDataBase()) {// if Database Not Exist
            copyDataBase();
        }

        myDataBase = getExistDataBaseFile();

        return myDataBase;
    }

    private SQLiteDatabase getExistDataBaseFile() {// this function to open an Exist database 

        SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
            public void preKey(SQLiteDatabase database) {
            }

            public void postKey(SQLiteDatabase database) {
                database.rawExecSQL("PRAGMA cipher_migrate;");

            }
        };
        return SQLiteDatabase.openOrCreateDatabase(FULL_DB_Path, password,
                null, hook);

    }


    private boolean checkDataBase() {// Check database file is already exist or not
        boolean checkDB = false;
        try {
            File dbfile = new File(FULL_DB_Path);
            checkDB = dbfile.exists();
        } catch (SQLiteException e) {
        }
        return checkDB;
    }


    public void db_delete() {// delete database
        File file = new File(FULL_DB_Path);
        if (file.exists()) {
            file.delete();
            System.out.println("delete database file.");
        }
    }

    private void copyDataBase() {//make a sub folder for database location and copy the database
        try {
            File fofo = new File(DATABASE_PATH);
            fofo.mkdirs();
            extractAssetToDatabaseDirectory(DATABASE_NAME);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

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

    public void extractAssetToDatabaseDirectory(String fileName)
            throws IOException {// copy the database

        int length;
        InputStream sourceDatabase = context.getAssets().open(fileName);
        File destinationPath = new File(FULL_DB_Path);
        OutputStream destination = new FileOutputStream(destinationPath);

        byte[] buffer = new byte[4096];
        while ((length = sourceDatabase.read(buffer)) > 0) {
            destination.write(buffer, 0, length);
        }
        sourceDatabase.close();
        destination.flush();
        destination.close();
    }

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

    public void onCreate(SQLiteDatabase db) {
    }

    public boolean changePassword(String newPassword) {// DataBase must be
                                                        // opened before
                                                        // changing Password

        try {
            if (myDataBase != null && myDataBase.isOpen()) {

                myDataBase.rawExecSQL("BEGIN IMMEDIATE TRANSACTION;");
                myDataBase.rawExecSQL("PRAGMA rekey = '" + newPassword + "';");

                this.close();
                myDataBase.close();

                return true;

            } else {

                Log.e("boolean changePassword()",
                        "Change Password Error : DataBase is null or not opened  !!");
                return false;
            }
        } catch (Exception e) {

            Log.e("boolean changePassword()",
                    "Change Password Error :ExecSQL Error !!");
            return false;

        }

    }

}

and this code inside activity :

     SQLiteDatabase db;
DataBaseHelper myDbHelper = new DataBaseHelper(MainActivity.this);
       db=myDbHelper.open("test");


  Cursor cursor=db.rawQuery("select * from t1", null);

这篇关于Sqlcipher __ CREATE TABLE android_metadata失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆