1. <div id="f8mbs"></div>
        您好,歡迎來到源碼搜藏網!分享精神,快樂你我!
        [加入VIP] 設為首頁 | 收藏本站 | 網站地圖 | Sitemap | TAG標簽
      2. 首 頁
      3. 在線工具
      4. jquery手冊
      5. 當前位置:首頁 > 安卓源碼 > 技術博客 >

        從Android資源中讀取SQLite數據庫的方法

        時間:2018-08-08 23:20 來源:互聯網 作者:源碼搜藏 瀏覽:收藏 挑錯 推薦 打印

        演示一種操作位于資產文件夾中的SQLite數據庫的方法 介紹 從Android Asset Resource改進SQLite文件處理性能 背景 Android SQLiteDatabase Android資產處理 SQLite VFS SQLite URI 使用代碼 一般來說,如果我們想從Android資產文件中讀取SQLite數據庫,我們必 演示一種操作位于資產文件夾中的SQLite數據庫的方法

        介紹

        從Android Asset Resource改進SQLite文件處理性能

        背景

        1. Android SQLiteDatabase
        2. Android資產處理
        3. SQLite VFS
        4. SQLite URI

        使用代碼

        一般來說,如果我們想從Android資產文件中讀取SQLite數據庫,我們必須將資產文件復制到本地文件夾,然后從本地文件中讀取數據庫。

        這種方法有一些缺點:

        1. 如果數據庫文件大小有點大,則會浪費磁盤使用量
        2. 浪費CPU
        3. 安全易受攻擊的
          用戶可以在root設備之后替換本地數據庫文件

        為了克服這些缺點,我們將推出支持Android資源資源的新SQLite VFS。

        SQLite在Unix OS上使用unix-vfs并在Window OS上使用win32-vfs

        Android包裝SQLite代碼并導出一些java接口(android.database.sqlite.SQLiteDatabase),但遺漏了原始SQLite實現的一些高級功能

        1. 自定義功能
        2. 加密
        3. URI文件語法
        4. VFS
        實際上Android已經在libsqlite.so中包含了上述功能,但是沒有提供Java接口/入口點,并且根據Android O +安全行為的變化,開發人員不得在后一個Android版本中訪問libsqlite.so

        幸運的是,SQLite開發人員已經提供了類似的Java包裝器:SQLite Android Bindings,它可以提供這些功能

        類名和成員名大多相同,因此您可以導入aar并更改您的java源導入

        import android.database.sqlite.SQLiteDatabase;

        import org.sqlite.database.sqlite.SQLiteDatabase;

        使用步驟

        1. 禁用
           build.gradle 中android資產的SQLiteDatabase文件的壓縮
          aaptOptions {
              noCompress 'db'
          }
        2. 實現SQLite VFS并注冊它
          sqlite3_vfs_register(&AndroidAsset::vfs, false);
          sqlite3_vfs_register(&AssetFDMap::vfs, false);
          sqlite3_vfs_register(&AssetFD::vfs, false);
        3. 使用custome URI打開asset文件夾中的數據庫文件 

        我為不同的scenerio實現了三個VFS 

        第一個VFS:android_asset

        Java(使用自定義SQLite URI打開SQLiteDatabase):

        try (SQLiteDatabase db = SQLiteDatabase.openDatabase("file:asset_db.db?vfs=android_asset&immutable=1&mode=ro", null, SQLiteDatabase.OPEN_READONLY)) {
           ................................
        }

        本機:

        static int xRead(sqlite3_file *file, void *buf, int iAmt, sqlite3_int64 iOfst) {
            vfs_file *f = (vfs_file *) file;
            int expectReadLen = (iAmt + iOfst > f->length) ? (f->length - iOfst) : iAmt;
            int readLen = pread64(f->fd, buf, expectReadLen, iOfst + f->offset);
            if (readLen < 0) {
                return SQLITE_IOERR_READ;
            } else if (readLen == expectReadLen) {
                return SQLITE_OK;
            } else {
                memset((__uint8_t *) buf + readLen, 0, iAmt - readLen);
                return SQLITE_IOERR_SHORT_READ;
            }
        }
        
        static int vfsOpen(sqlite3_vfs *vfs, const char *path, sqlite3_file *file, int flags,
                           int *outflags) {
        
            ALOGD("%s:: path=%s flags=%x", __FUNCTION__, path, flags);
            if (g_AAssetManager == NULL) {
                return SQLITE_ERROR;
            }
            vfs_file *f = (vfs_file *) file;
            f->pMethods = &vfs_io_methods;
            AAsset *asset = AAssetManager_open(g_AAssetManager, path, AASSET_MODE_RANDOM);
            if (asset == NULL) {    //if the asset file don't exist
                return SQLITE_NOTFOUND;
            }
            f->fd = AAsset_openFileDescriptor64(asset, &f->offset, &f->length);
            AAsset_close(asset);
            if (f->fd < 0) {  //if the asset file is compressed
                return SQLITE_NOTFOUND;
            }
            *outflags = flags;
            return SQLITE_OK;
        }

        第二個VFS:asset_fd_map

        Java(使用自定義SQLite URI打開SQLiteDatabase):

        try (AssetFileDescriptor afd = getAssets().openFd("asset_db.db")) {
            try (SQLiteDatabase db = SQLiteDatabase.openDatabase(String.format("file:%X_%X_%X?vfs=asset_fd_map&immutable=1&mode=ro", afd.getParcelFileDescriptor().getFd(), afd.getStartOffset(), afd.getLength()), null, SQLiteDatabase.OPEN_READONLY)) {
             .................................
          }
        }

        本機:

        static int xRead(sqlite3_file *file, void *buf, int iAmt, sqlite3_int64 iOfst) {
            vfs_file *f = (vfs_file *) file;
            int expectReadLen = (iAmt + iOfst > f->length) ? (f->length - iOfst) : iAmt;
            memcpy(buf, (__uint8_t *) f->address + iOfst + f->offset, expectReadLen);
            int readLen = expectReadLen;
            return SQLITE_OK;
        }
        
        static int vfsOpen(sqlite3_vfs *vfs, const char *path, sqlite3_file *file, int flags,
                           int *outflags) {
        
            ALOGD("%s:: path=%s flags=%x", __FUNCTION__, path, flags);
            vfs_file *f = (vfs_file *) file;
            f->pMethods = &vfs_io_methods;
            if (3 > sscanf(path, "%x_%llx_%llx", &f->fd, &f->offsetFileStart, &f->length)) {
                return SQLITE_ERROR;
            }
            //because mmap() require the offset must be on the page boundary
            __int64_t offsetToPage = (f->offsetFileStart / 4096) * 4096;
            f->offsetMapStart = f->offsetFileStart - offsetToPage;
            f->mapLength = f->length + f->offsetMapStart;
        
            f->address = mmap64(NULL, f->mapLength, PROT_READ, MAP_PRIVATE, f->fd, offsetToPage);
            if (f->address == MAP_FAILED) {
                return SQLITE_ERROR;
            }
            *outflags = flags;
            return SQLITE_OK;
        }

        第三個VFS:asset_fd

        Java(使用自定義SQLite URI打開SQLiteDatabase):

        try (AssetFileDescriptor afd = getAssets().openFd("asset_db.db")) {
            try (SQLiteDatabase db = SQLiteDatabase.openDatabase(String.format("file:%X_%X_%X?vfs=asset_fd&immutable=1&mode=ro", afd.getParcelFileDescriptor().getFd(), afd.getStartOffset(), afd.getLength()), null, SQLiteDatabase.OPEN_READONLY)) {
             .................................
          }
        }

        本機:

        static int xRead(sqlite3_file *file, void *buf, int iAmt, sqlite3_int64 iOfst) {
            vfs_file *f = (vfs_file *) file;
            int expectReadLen = (iAmt + iOfst > f->length) ? (f->length - iOfst) : iAmt;
            int readLen = pread64(f->fd, buf, expectReadLen, iOfst + f->offset);
            if (readLen < 0) {
                return SQLITE_IOERR_READ;
            } else if (readLen == expectReadLen) {
                return SQLITE_OK;
            } else {
                memset((__uint8_t *) buf + readLen, 0, iAmt - readLen);
                return SQLITE_IOERR_SHORT_READ;
            }
        }
        
        static int vfsOpen(sqlite3_vfs *vfs, const char *path, sqlite3_file *file, int flags,
                           int *outflags) {
        
            ALOGD("%s:: path=%s flags=%x", __FUNCTION__, path, flags);
            vfs_file *f = (vfs_file *) file;
            f->pMethods = &vfs_io_methods;
            if (3 > sscanf(path, "%x_%llx_%llx", &f->fd, &f->offset, &f->length)) {
                return SQLITE_ERROR;
            }
            *outflags = flags;
            return SQLITE_OK;
        }

        在演示項目中,我比較了不同的方法。

        經過時間差異似乎不是太大,可能是因為性能瓶頸是SQLite內部數據處理,而不是文件處理

        從Android資源中讀取SQLite數據庫的方法
        從Android資源中讀取SQLite數據庫的方法轉載http://www.rhcg.tw/appboke/38808.html
        標簽:網站源碼
        辽宁十一选五单双