为什么存在SQLite文件,但openDatabase给出错误?

时间:2019-06-15 20:21:30

标签: android sqlite kotlin

我知道这是一个重复的问题,但是堆栈溢出中的旧问题对我没有帮助,因为情况已经改变。

a)我已将我的 SQLite 文件your.db复制到中的 asset 文件夹(只读)中Android Studio

b)在我的应用中,我已通过以下方式将资产从资产复制到内部存储空间:

// Internal Storage Path: (/Data/User/0/*myapppath*/files)
val name="your.db"
val f = this.assets.open(name)
val SQLContent = f.bufferedReader().use{ it.readText()}
f.close()
val file = File(this.filesDir, name)
file.writeText(SQLContent)

c)我已经检查过我的文件是否确实复制到了 Android 手机中 以下代码显示在按钮上显示OK。是的。

val file = File(this.filesDir, "your.db")
if (file.exists()) result="Ok" else result="Argh"I

d)下面的代码用于打开我的数据库(已存储在内部存储器中)。但是,由于系统找不到我的数据库,因此出现错误。

String DBPath  = file.getabsolutePath()
SQLiteDatabase db = SQLiteDatabase.openDatabase(DBPath,
    null, SQLiteDatabase.OPEN_READWRITE)

我知道推荐的 SQLite 数据库位置是...\databases而不是...\files,但是即使那样,给出错误也没有意义,因为文件实际上是在那里。

更新: 使用@commonsware注释,我使用了设备文件资源管理器。因此,我注意到SQLiteDatabase.openDatabase在文件名中放置了corrupt前缀,但是,错误是

Error Code : 1294 (SQLITE_CANTOPEN_ENOENT)
Caused By : Specified directory or database file does not exist.
    (unknown error (code 1294): Could not open database)

更新2

使用@commonsware接受的答案,我替换了用于复制二进制版本文件的代码。

将文件从资产复制到内部存储空间

val arq = this.assets.open(nome)
val file = File(this.filesDir, nome)
val saida = file.outputStream()
arq.copyTo(saida)
saida.close()
arq.close()

现在,它可以正常运行。我打开SQLite,使用游标运行查询,扫描游标,打印记录,关闭游标并关闭数据库。没有其他错误。

使用设备文件资源管理器工具(菜单 View 工具Windows )时,它将显示私有应用程序文件。当我将SQLite文件复制回我的计算机时(在右侧按钮上下文菜单中使用copy as)在复制期间仍然失败。我认为此选项尝试将文件复制为文本而不是二进制文件。

2 个答案:

答案 0 :(得分:3)

我没有注意到您在编辑中添加了文件复制代码。

val SQLContent = f.bufferedReader().use{ it.readText()}

SQLite数据库是二进制文件,而不是文本。使用readBytes()writeBytes(),而不是readText()writeText()

答案 1 :(得分:1)

资产始终是R / O,因为它们是APK文件的一部分。这是Java中的示例方法,该方法返回一个R / W句柄(其中DATABASE_FILENAME是要打开的文件名):

private static SQLiteDatabase db;
private Context mContext;

@Nullable
public SQLiteDatabase getDatabase() {

    /* attempting to return early */
    if(db != null && db.isOpen()) {
        return db;
    } else {
        SQLiteDatabase db = null;
        File path = this.mContext.getDatabasePath(Constants.DATABASE_FILENAME);
        if (path.exists()) {
            try {
                db = SQLiteDatabase.openDatabase(path.getAbsolutePath(), null, SQLiteDatabase.OPEN_READWRITE);
            } catch (SQLiteCantOpenDatabaseException e) {
                Log.e(LOG_TAG, e.getMessage());
            }
        } else {
            Log.e(LOG_TAG, path.getAbsolutePath() + " does not exist.");
        }
        return db;
    }
}

(普通),期望的数据库目录为/databases,而不是/files。并且,如果打算从资产中打开R / O(例如,从资产中导入),则必须标记OPEN_READONLY ...这可能是SQLITE_CANTOPEN_ENOENT与标记{ {1}}和R / O资源;两次调用OPEN_READWRITE也是导入数据时要考虑的问题。我只使用db.close()来插入...,这是搞乱数据库文件的可靠选择-甚至可以插入本地化的字符串。二进制副本在内容本地化方面严重失败。