如何将 SQLite 数据库嵌入到应用程序中?

Posted

技术标签:

【中文标题】如何将 SQLite 数据库嵌入到应用程序中?【英文标题】:How can I embed an SQLite database into an application? 【发布时间】:2011-08-03 09:04:57 【问题描述】:

我认为我有一些基本的理解问题,所以也许有人能够提供帮助:-)

我正在使用 Eclipse 开发一个 android 应用程序,这个应用程序将使用一个数据库(将只实现从数据库中读取)。该数据库包含大约 4,000 个条目,即不能通过源代码创建和填充数据库。因此,我已经提前创建了包含所有记录的数据库。

但是我怎样才能将这个数据库文件“嵌入”到我的应用程序中然后访问它呢?数据库的文件大小约为 500 kB。从远程服务器下载也不是一种选择,因为这是不允许的。

谢谢, 罗伯特

【问题讨论】:

【参考方案1】:

ReignDesign 博客上标题为 Using your own SQLite database in Android applications 的好文章。基本上你预先创建了你的数据库,把它放在你的 apk 中的 assets 目录中,并在第一次使用时复制到“/data/data/YOUR_PACKAGE/databases/”目录。

【讨论】:

【参考方案2】:

我通过以下方式解决了这个问题:

    file.db 添加到项目/资产文件夹中;

    写下一节课:

    public class LinnaeusDatabase extends SQLiteOpenHelper
    
        private static String DATABASE_NAME = "Dragonfly.db";
        public final static String DATABASE_PATH = "/data/data/com.kan.linnaeus/databases/";
        private static final int DATABASE_VERSION = 1;
    
        private SQLiteDatabase dataBase;
        private final Context dbContext;
    
        public LinnaeusDatabase(Context context) 
            super(context, DBActivity.DatabaseName, null, DATABASE_VERSION);
            this.dbContext = context;
            DATABASE_NAME = DBActivity.DatabaseName;
            // checking database and open it if exists
            if (checkDataBase()) 
                openDataBase();
             else
            
                try 
                    this.getReadableDatabase();
                    copyDataBase();
                    this.close();
                    openDataBase();
    
                 catch (IOException e) 
                    throw new Error("Error copying database");
                
                Toast.makeText(context, "Initial database is created", Toast.LENGTH_LONG).show();
            
        
    
        private void copyDataBase() throws IOException
            InputStream myInput = dbContext.getAssets().open(DATABASE_NAME);
            String outFileName = DATABASE_PATH + DATABASE_NAME;
            OutputStream myOutput = new FileOutputStream(outFileName);
    
            byte[] buffer = new byte[1024];
            int length;
            while ((length = myInput.read(buffer))>0)
                myOutput.write(buffer, 0, length);
            
    
            myOutput.flush();
            myOutput.close();
            myInput.close();
        
    
        public void openDataBase() throws SQLException 
            String dbPath = DATABASE_PATH + DATABASE_NAME;
            dataBase = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);
        
    
        private boolean checkDataBase() 
            SQLiteDatabase checkDB = null;
            boolean exist = false;
            try 
                String dbPath = DATABASE_PATH + DATABASE_NAME;
                checkDB = SQLiteDatabase.openDatabase(dbPath, null,
                SQLiteDatabase.OPEN_READONLY);
             catch (SQLiteException e) 
                Log.v("db log", "database does't exist");
            
    
            if (checkDB != null) 
                exist = true;
                checkDB.close();
            
            return exist;
        
    
    

【讨论】:

【参考方案3】:

在对this answer 的评论中,CommonsWare 建议不要使用@evilone 在此处提出的相同方法(即,自己从资产中复制数据库)。相反,您应该使用久经考验的SQLiteAssetHelper。我在 Android Studio 中使用过,效果很好。

directions 相当清晰。以下是一些关键摘录:

如果您使用的是 Gradle 构建系统,只需添加以下内容 build.gradle 文件中的依赖项:

dependencies 
    compile 'com.readystatesoftware.sqliteasset:sqliteassethelper:+'

像平常一样扩展SQLiteAssetHelper SQLiteOpenHelper, 为构造函数提供数据库名称和版本号:

public class MyDatabase extends SQLiteAssetHelper 

    private static final String DATABASE_NAME = "northwind.db";
    private static final int DATABASE_VERSION = 1;

    public MyDatabase(Context context) 
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    

将您的数据库放入assets/databases/northwind.db(使用您拥有的任何数据库名称)。

第一次使用数据库 getReadableDatabase()getWritableDatabase() 被调用。

【讨论】:

【参考方案4】:

我过去通过将 JSON 文件存储在 res/raw 资源中的应用程序中,然后在首次加载时加载文件来完成此操作。从那里,您可以使用批量插入模式批量导入条目。请参阅 my database loader for Units 作为此技术的示例。 res/raw 样式的一个好处是您可以使用 Android 资源选择系统将数据本地化到不同的区域,因此您可以针对不同的语言或区域拥有不同的数据库(或其中的一部分)。

您还可以将原始 SQL 转储放在类似的文件中,并在首次加载时加载该文件。您可以使用openRawResource(int) 从资源中获取文件。我建议这样做,而不是存储预制的 sqlite 数据库文件,以增加 sqlite 版本之间的兼容性,并使数据库维护更容易(从应用程序开发生命周期 POV)。

批量加载时,请确保使用事务,因为这将有助于加快加载速度并使加载更加可靠。

【讨论】:

史蒂夫,我喜欢这个主意。您是否有在线代码示例、博客文章或教程? 我已经更新了我的答案,其中包含一些使用这种技术的代码的链接。 据我所知,JSON 文件将存储在一个字符串变量中,然后传递给 Android 中的 JSON 解析,对吗?这个 JSON 文件/字符串可以有多大?在我的应用程序中,它大约为 250-500 kB。 是的,这可能有问题。在您的情况下,如果您想以不只是 sqlite 数据库的格式存储它,那么将其存储为 SQL 可能是有意义的。我想知道在二进制/版本兼容性方面,预先创建数据库会有多少问题。

以上是关于如何将 SQLite 数据库嵌入到应用程序中?的主要内容,如果未能解决你的问题,请参考以下文章

将 sqlite 数据库嵌入到 c++ 可执行文件中

在核心数据应用程序中嵌入预定义的 SQLITE 文档

SQLite 库可以嵌入(链接)到 Delphi 可执行文件吗?

如何在Linux下用C/C++语言操作数据库sqlite3

SQLite学习手册

使用嵌入式 sqlite 部署 winform 应用程序