未能将 db '/data/data/my.easymedi.controller/databases/EasyMediInfo.db' 的区域设置更改为 'en_US'

2022-09-02 21:25:11

在我的Android应用程序中,有一个预定义的数据库,它位于assets文件夹中。

我创建了一个表,其中包含一个名为的列,其中包含一条记录。android_metadatalocaleen_US

在我的应用程序中,用户应输入他/她的详细信息,然后单击保存按钮。

当点击保存按钮时,我得到了以下错误;

10-21 09:37:06.010: E/SQLiteLog(6278): (11) [00bb9c9ce4] 10-21 09:37:06.010: E/SQLiteLog(6278): (11) [00bb9c9ce4] 10-2 第 50780 行的数据库损坏 1 09:37:06.010: E/SQLiteLog(6278): (11) 语句在 16 处中止: [从 android_metadata 选择区域设置,按区域设置选择空顺序 DESC 限制 1] 10-21 09:37:06.160: E/SQLiteDatabase(6278): 无法打开数据库 '/data/data/my.easymedi.controller/databases/EasyMediInfo.db'。10-21 09:37:06.160: E/SQLiteDatabase(6278): android.database.sqlite.SQLiteException: 无法将 db '/data/my.easymedi.controller/databases/EasyMediInfo.db' 的区域设置更改为 'en_US'。10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.database.sqlite.SQLiteConnection.setLocaleFromConfiguration(SQLiteConnection.java:386) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:218) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193) 10-21 09:37:06.160: E/SQLiteDatabase(6278): atandroid.database.sqlite.SQLiteConnectionPool.openConnectionLock(SQLiteConnectionPool.java:463) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:804) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:789) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669) 10-21 09:37:06.160: E/SQLiteDatabase(6278): atmy.easymedi.db.DBHelper.openDataBase(DBHelper.java:153) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at my.easymedi.controller.AddNewPerson.onClick(AddNewPerson.java:202) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.view.View.performClick (View.java:4202) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.view.View$PerformClick.run(View.java:17340) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.os.Handler.handleCallback(Handler.java:725) 10-2109:37:06.160: E/SQLiteDatabase(6278): at android.os.Handler.dispatchMessage(Handler.java:92) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.os.Looper.loop(Looper.java:137) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.app.ActivityThread.main(ActivityThread.java:5039) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at java.lang.reflect.Method.invokeNative(Native Method) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at java.lang.reflect.Method.invoke(Method.java:511) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at com.android.internal.os.Zy goteInit.main(ZygoteInit.java:560) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at dalvik.system.NativeStart.main(Native Method) 10-21 09:37:06.160: E/SQLiteDatabase(6278): Caused by: android.database.sqlite.SQLiteDatabaseCorruptException: database disk image image格式不正确 (代码 11) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.database.sqlite.SQLiteConnection.nativeExecuteForString(Native Method) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:634) 10-21 09:37:06.160: E/SQLiteDatabase(6278): at android.database.sqlite.SQLiteConnection.setLocaleFromConfiguration(SQLiteConnection.java:367) 10-21 09:37:06.160: E/SQLiteDatabase(6278): ...另外 22

我的DBHelper类如下;

package my.easymedi.db;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import my.easymedi.entity.Person;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import android.widget.Toast;

public class DBHelper extends SQLiteOpenHelper {

 private static final String pkg = "my.easymedi.controller";
 private static String DB_PATH = "";
 private static String DB_NAME = "EasyMediInfo.db";
 private static final int DB_VERSION = 1;
 private final Context myContext;
 private SQLiteDatabase myDatabase;

 public DBHelper(Context context) {
  super(context, DB_NAME, null, DB_VERSION);
  // this.myContext = context;
  if (android.os.Build.VERSION.SDK_INT >= 4.2) {
   DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
  } else {
   DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
  }
  this.myContext = context;
 }

 public void createDataBase() {
  boolean dbExist = checkDataBase();
  System.out.println("===" + dbExist + "===");
  if (dbExist) {
   // do nothing - database already exist
  } else {

   this.getReadableDatabase();
   this.close();
   try {
    copyDataBase();
    Log.d("CREATE_DB", "createDatabase database created");
   } catch (IOException e) {
    Toast.makeText(myContext, e.getMessage(), Toast.LENGTH_SHORT)
     .show();
    Log.d("CREATE_DB", e.getMessage());
   }
  }
 }

 private void copyDataBase() throws IOException {
  System.out.println("***copy db***");
  InputStream databaseInput = null;
  /* Path to copy the database */
  String outFileName = DB_PATH + DB_NAME;
  /* open the empty database as an output stream */
  OutputStream databaseOutput = new FileOutputStream(outFileName);
  /* open the local database as the input stream */
  databaseInput = myContext.getAssets().open(DB_NAME);

  /* Transfer byte from byte from input file to output file */
  byte[] buffer = new byte[1024];
  int length = databaseInput.read(buffer);
  while (length > 0) {
   databaseOutput.write(buffer, 0, length);
   //databaseOutput.flush();
  }
  databaseOutput.flush();
  databaseInput.close();
  databaseOutput.close();
 }

 private boolean checkDataBase() {
  File dbFile = new File(DB_PATH + DB_NAME);
  return dbFile.exists();
  /*SQLiteDatabase checkDB = null;
  try {
    String myPath = DB_PATH + DB_NAME;
    checkDB = SQLiteDatabase.openDatabase(myPath, null,
            SQLiteDatabase.NO_LOCALIZED_COLLATORS);
  } catch (SQLiteException e) {
    Toast.makeText(myContext, e.getMessage(), Toast.LENGTH_SHORT)
            .show();
    Log.d("Check_DB", e.getMessage());
  }
  if (checkDB != null) {
    String str = "checked";
    System.out.println("====" + str + "====");
    checkDB.close();
  }
  return checkDB != null ? true : false;*/
 }

 /* Open the database */
 public boolean openDataBase() {
  String myPath = DB_PATH + DB_NAME;
  Toast.makeText(myContext, myPath, Toast.LENGTH_SHORT).show();
  myDatabase = SQLiteDatabase.openDatabase(myPath, null,
   SQLiteDatabase.OPEN_READWRITE);
  if (myDatabase != null) {
   System.out.println("====database opened====");
  } else {
   System.out.println("====error opening database====");
  }
  return myDatabase != null ? true : false;
 }

 public void closeDatabase() {
  if (myDatabase != null) {
   myDatabase.close();
  }
 }

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

 }

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

 }

 public boolean insertIntoDatabase(String table, ContentValues values) {
  try {
   myDatabase.insert(table, null, values);
   Log.d("INSERT", "Information Saved");
   return true;
  } catch (Exception e) {
   // TODO Auto-generated catch block
   Log.d("INSERT", e.toString());
   return false;
  }
 }
}

这是我的保存按钮的代码段;

case R.id.btnSave: personName = etName.getText().toString();
date_of_birth = tvDOB.getText().toString();
age = tvAge.getText().toString();

int selected_rb_ID = genderGrp.getCheckedRadioButtonId();
RadioButton rb = (RadioButton) findViewById(selected_rb_ID);
gender = rb.getText().toString();
bloodGrp = spiBloodGrp.getSelectedItem().toString();

Person person = new Person();
person.setName(personName);
person.setDate_of_birth(date_of_birth);
person.setAge(age);
person.setGender(gender);
person.setBloodGrp(bloodGrp);

ContentValues values = new ContentValues();
values.put(COLUMN_PERSON_NAME, person.getName());
values.put(COLUMN_DOB, person.getDate_of_birth());
values.put(COLUMN_AGE, person.getAge());
values.put(COLUMN_GENDER, person.getGender());
values.put(COLUMN_BLOODGRP, person.getBloodGrp());

DBHelper dbHelper = new DBHelper(this);
dbHelper.createDataBase();
dbHelper.openDataBase();
if (dbHelper.insertIntoDatabase("EMPerson", values)) {
 Toast.makeText(
  getApplicationContext(),
  "Data has been saved successfully",
  Toast.LENGTH_SHORT
 ).show();
} else {
 Toast.makeText(
  getApplicationContext(),
  "Oops ! Try again",
  Toast.LENGTH_SHORT
 ).show();
}
dbHelper.closeDatabase();

break;

在我的主要活动中,我通过调用此代码段创建了数据库。

final DBHelper helper = new DBHelper(this);
helper.createDataBase();

此错误的含义是什么,我该如何解决它?


答案 1

您的函数从资产文件夹中复制 db()。而且,数据库似乎是使用与 不同的区域设置创建的。copyDataBase()EasyMediInfo.db'en_US'

编辑

尝试更改:

myDatabase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);

自:

myDatabase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS | SQLiteDatabase.OPEN_READWRITE);

答案 2

当设置Locale到zh_CN时,我得到了同样的错误。我没有编写新代码来直接使用SQLiteDatabase,而是制作了一个修改后的SQLiteOpenHelper:

/**
 * A simplified version of SKD's SQLiteOpenHelper(only writable), original doc below
 *
 * A helper class to manage database creation and version management.
 *
 * <p>You create a subclass implementing {@link #onCreate}, {@link #onUpgrade} and
 * optionally {@link #onOpen}, and this class takes care of opening the database
 * if it exists, creating it if it does not, and upgrading it as necessary.
 * Transactions are used to make sure the database is always in a sensible state.
 *
 * <p>This class makes it easy for {@link android.content.ContentProvider}
 * implementations to defer opening and upgrading the database until first use,
 * to avoid blocking application startup with long-running database upgrades.
 *
 * <p>For an example, see the NotePadProvider class in the NotePad sample application,
 * in the <em>samples/</em> directory of the SDK.</p>
 *
 * <p class="note"><strong>Note:</strong> this class assumes
 * monotonically increasing version numbers for upgrades.</p>
 */
public abstract class SQLiteOpenHelper {
    private static final String TAG = SQLiteOpenHelper.class.getSimpleName();


    private final Context mContext;
    private final String mName;
    private final CursorFactory mFactory;
    private final int mNewVersion;

    private SQLiteDatabase mDatabase;
    private boolean mIsInitializing;
    private boolean mEnableWriteAheadLogging;
    private final DatabaseErrorHandler mErrorHandler;

    /**
     * Create a helper object to create, open, and/or manage a database.
     * This method always returns very quickly.  The database is not actually
     * created or opened until one of {@link #getWritableDatabase} or
     * {@link #getReadableDatabase} is called.
     *
     * @param context to use to open or create the database
     * @param name of the database file, or null for an in-memory database
     * @param factory to use for creating cursor objects, or null for the default
     * @param version number of the database (starting at 1); if the database is older,
     *     {@link #onUpgrade} will be used to upgrade the database; if the database is
     *     newer, {@link #onDowngrade} will be used to downgrade the database
     */
    public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
        this(context, name, factory, version, null);
    }

    /**
     * Create a helper object to create, open, and/or manage a database.
     * The database is not actually created or opened until one of
     * {@link #getWritableDatabase} or {@link #getReadableDatabase} is called.
     *
     * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
     * used to handle corruption when sqlite reports database corruption.</p>
     *
     * @param context to use to open or create the database
     * @param name of the database file, or null for an in-memory database
     * @param factory to use for creating cursor objects, or null for the default
     * @param version number of the database (starting at 1); if the database is older,
     *     {@link #onUpgrade} will be used to upgrade the database; if the database is
     *     newer, {@link #onDowngrade} will be used to downgrade the database
     * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
     * corruption, or null to use the default error handler.
     */
    public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
            DatabaseErrorHandler errorHandler) {
        if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);

        mContext = context;
        mName = name;
        mFactory = factory;
        mNewVersion = version;
        mErrorHandler = errorHandler;
    }

    /**
     * Return the name of the SQLite database being opened, as given to
     * the constructor.
     */
    public String getDatabaseName() {
        return mName;
    }

    /**
     * Enables or disables the use of write-ahead logging for the database.
     *
     * Write-ahead logging cannot be used with read-only databases so the value of
     * this flag is ignored if the database is opened read-only.
     *
     * @param enabled True if write-ahead logging should be enabled, false if it
     * should be disabled.
     *
     * @see SQLiteDatabase#enableWriteAheadLogging()
     */
    public void setWriteAheadLoggingEnabled(boolean enabled) {
        synchronized (this) {
            if (mEnableWriteAheadLogging != enabled) {
                if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
                    if (enabled) {
                        mDatabase.enableWriteAheadLogging();
                    } else {
                        mDatabase.disableWriteAheadLogging();
                    }
                }
                mEnableWriteAheadLogging = enabled;
            }
        }
    }

    /**
       Simplified getWritableDatabase from SDK source
     */
    public SQLiteDatabase getWritableDatabase() {
        synchronized (this) {
            return getDatabaseLocked();
        }
    }

    private SQLiteDatabase getDatabaseLocked() {
        // always get writable database
        if (mDatabase != null) {
            if (!mDatabase.isOpen()) {
                // Darn!  The user closed the database by calling mDatabase.close().
                mDatabase = null;
            } else if (!mDatabase.isReadOnly()) {
                // The database is already open for business.
                return mDatabase;
            }
        }

        if (mIsInitializing) {
            throw new IllegalStateException("getDatabase called recursively");
        }

        SQLiteDatabase db = mDatabase;
        try {
            mIsInitializing = true;

            if (db == null && mName == null) {
                db = SQLiteDatabase.create(null);
            } else if (db == null) {
                try {
                    final String path = mContext.getDatabasePath(mName).getPath();
                    db = SQLiteDatabase.openDatabase(path, mFactory,
                            (SQLiteDatabase.CREATE_IF_NECESSARY
                             | SQLiteDatabase.OPEN_READWRITE
                             | SQLiteDatabase.NO_LOCALIZED_COLLATORS),
                            mErrorHandler);
                } catch (SQLiteException ex) {
                    throw ex;
                }
            }

            onConfigure(db);

            final int version = db.getVersion();
            if (version != mNewVersion) {

                db.beginTransaction();
                try {
                    if (version == 0) {
                        onCreate(db);
                    } else {
                        if (version > mNewVersion) {
                            onDowngrade(db, version, mNewVersion);
                        } else {
                            onUpgrade(db, version, mNewVersion);
                        }
                    }
                    db.setVersion(mNewVersion);
                    db.setTransactionSuccessful();
                } finally {
                    db.endTransaction();
                }
            }

            onOpen(db);

            mDatabase = db;
            return db;
        } finally {
            mIsInitializing = false;
            if (db != null && db != mDatabase) {
                db.close();
            }
        }
    }

    /**
     * Close any open database object.
     */
    public synchronized void close() {
        if (mIsInitializing) throw new IllegalStateException("Closed during initialization");

        if (mDatabase != null && mDatabase.isOpen()) {
            mDatabase.close();
            mDatabase = null;
        }
    }

    /**
     * Called when the database connection is being configured, to enable features
     * such as write-ahead logging or foreign key support.
     * <p>
     * This method is called before {@link #onCreate}, {@link #onUpgrade},
     * {@link #onDowngrade}, or {@link #onOpen} are called.  It should not modify
     * the database except to configure the database connection as required.
     * </p><p>
     * This method should only call methods that configure the parameters of the
     * database connection, such as {@link SQLiteDatabase#enableWriteAheadLogging}
     * {@link SQLiteDatabase#setForeignKeyConstraintsEnabled},
     * {@link SQLiteDatabase#setLocale}, {@link SQLiteDatabase#setMaximumSize},
     * or executing PRAGMA statements.
     * </p>
     *
     * @param db The database.
     */
    public void onConfigure(SQLiteDatabase db) {}

    /**
     * Called when the database is created for the first time. This is where the
     * creation of tables and the initial population of the tables should happen.
     *
     * @param db The database.
     */
    public abstract void onCreate(SQLiteDatabase db);

    /**
     * Called when the database needs to be upgraded. The implementation
     * should use this method to drop tables, add tables, or do anything else it
     * needs to upgrade to the new schema version.
     *
     * <p>
     * The SQLite ALTER TABLE documentation can be found
     * <a href="http://sqlite.org/lang_altertable.html">here</a>. If you add new columns
     * you can use ALTER TABLE to insert them into a live table. If you rename or remove columns
     * you can use ALTER TABLE to rename the old table, then create the new table and then
     * populate the new table with the contents of the old table.
     * </p><p>
     * This method executes within a transaction.  If an exception is thrown, all changes
     * will automatically be rolled back.
     * </p>
     *
     * @param db The database.
     * @param oldVersion The old database version.
     * @param newVersion The new database version.
     */
    public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);

    /**
     * Called when the database needs to be downgraded. This is strictly similar to
     * {@link #onUpgrade} method, but is called whenever current version is newer
     * than requested one.
     * However, this method is not abstract, so it is not mandatory for a customer to
     * implement it. If not overridden, default implementation will reject downgrade and
     * throws SQLiteException
     *
     * <p>
     * This method executes within a transaction.  If an exception is thrown, all changes
     * will automatically be rolled back.
     * </p>
     *
     * @param db The database.
     * @param oldVersion The old database version.
     * @param newVersion The new database version.
     */
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        throw new SQLiteException("Can't downgrade database from version "
                + oldVersion + " to " + newVersion);
    }

    /**
     * Called when the database has been opened.  The implementation
     * should check {@link SQLiteDatabase#isReadOnly} before updating the
     * database.
     * <p>
     * This method is called after the database connection has been configured
     * and after the database schema has been created, upgraded or downgraded as necessary.
     * If the database connection must be configured in some way before the schema
     * is created, upgraded, or downgraded, do it in {@link #onConfigure} instead.
     * </p>
     *
     * @param db The database.
     */
    public void onOpen(SQLiteDatabase db) {}
}

推荐