SQLite姓氏数据库首字母检索开发

具体讲解看博主的另一篇文章。

基于Android的SQLite姓氏数据库构建与首字母检索模块开发实战(最少代码量)-CSDN博客https://blog.csdn.net/weixin_72689660/article/details/160410622?sharetype=blogdetail&sharerId=160410622&sharerefer=PC&sharesource=weixin_72689660&spm=1011.2480.3001.8118

java 复制代码
package com.mySQLiteTest.SQLiteTest;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

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

/**
 * @File Name: mySurnameDatabase .java
 * @Date: April 22, 2026
 * @Version: 1.0
 * @Author: 施棠海
 * @描述: 数据库安全初始化、安全获取数据。
 */

public class mySurnameDatabase {
    private static final String TAG = "mySurnameDatabase";

    private static final String DB_NAME    = "SurnameInitialDb.db"  ;   // 数据库名
    private static final String TABLE_NAME = "HundredFamilySurnames";   // 表名

    private static mySurnameDatabase instance;

    private Context mContext;
    private SQLiteDatabase database;

    private String dbPath;

    private boolean initialized = false;

    public mySurnameDatabase(Context context){
        mContext = context.getApplicationContext();
        // 获取数据库文件路径(指的是如果db文件拷贝,设备会默认放在哪个路径下,不需要这个文件当前真的在这个目录下存在)
        dbPath = mContext.getDatabasePath(DB_NAME).getAbsolutePath();
    }

    public static synchronized mySurnameDatabase getInstance(Context context){
        if (instance == null){
            // 第一次创建单例时调用构造函数
            instance = new mySurnameDatabase(context);
        }
        return instance;
    }

    public void initDB() {
        try {
            File dbFile = new File(dbPath);
            // 开始拷贝文件
            File dbFilePath = dbFile.getParentFile();
            if (!dbFilePath.exists()){  // 如果父目录不存在就递归创建所有父目录
                dbFilePath.mkdirs();
            }
            // 如果数据库文件已经存在,则删除
            if (dbFile.exists()){
                dbFile.delete();
            }

            // 创建数据库文件
            // InputStream 打开一条读取管道,程序可以从中一个字节一个字节地取数据
            // FileOutputStream 打开一条写入管道,程序通过它创建/覆盖文件并写入字节。创建一个文件输出流,向指定的文件写入数据。
            try (InputStream input = mContext.getAssets().open(DB_NAME);FileOutputStream output = new FileOutputStream(dbFile)){
                // 获取数据库文件大小
                int dbAvailable = input.available();
                Debug.i(TAG,"已发现数据库文件,大小:"+dbAvailable+" bytes");
                if (dbAvailable<=0){
                    // 发送错误信息
                    throw new IOException(DB_NAME+" 文件为空或不存在");
                }
                // 缓冲区buffer,用于存储数据库文件
                byte[] buffer = new byte[1024];
                int byteSizeAll = 0;
                int byteSize = 0;
                // 读取数据库文件
                // input.read(byte[] b)方法返回读取的字节数,如果返回0,则说明文件读取完毕。读取时会把读取的文件内容缓存到buffer中
                while ((byteSize = input.read(buffer)) > 0){
                    // 向指定的目录下写入指定的文件
                    output.write(buffer,0,byteSize);
                    byteSizeAll += byteSize;
                }
                // 刷新缓冲区,确保数据写入。刷新此输出流并强制将任何缓冲的输出字节写出
                output.flush();
                Debug.i(TAG,DB_NAME+" 文件复制完成。大小: "+byteSizeAll+" bytes。 路径: "+dbPath);
            }

            // 打开数据库并设置只读模式
            database = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READONLY);
            initialized = true;
            Debug.i(TAG,"数据库初始化完成");
        } catch (IOException e) {
            Debug.e(TAG,"数据库初始化失败 "+ e.getMessage(),e);
            initialized = false;
        }
    }

    public String getInitial(String Surname){
        try {
            // 若未初始化,则初始化
            if(!initialized && database == null){
                Debug.i(TAG,"未初始化,执行初始化程序");
                initDB();
            }
            // 若初始化失败,则返回空值
            if(!initialized && database == null){
                Debug.i(TAG,"初始化失败,返回空值");
                return "";
            }
            // 若数据库未打开,则打开数据库
            if(!database.isOpen()){
                database = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READONLY);
            }

            // 查询数据库并获取结果集
            Cursor cursor = database.rawQuery(
                    // SELECT 字段 FROM 表名 WHERE 条件
                    "SELECT Initial FROM " + TABLE_NAME + " WHERE Name = ?",
                    // 把参数放入数组中,SQLite会自动将问号替换为参数,防止SQL注入攻击。
                    new String[]{Surname}
            );
            String initial = null;
            // 使光标移到结果集的第一行,若当前行存在结果则返回 true,否则返回 false
            if(cursor.moveToFirst()){
                // 获取当前行指定列的值
                initial = cursor.getString(cursor.getColumnIndexOrThrow("Initial"));
            }
            // 关闭结果集,否则会内存泄露。
            cursor.close();
            Debug.i(TAG,"找到的首字母为 "+initial);
            return initial == null?"":initial;
        } catch (Exception e) {
            Debug.e(TAG,"获取首字母失败 "+e.getMessage(),e);
            return "";
        }
    }

    public void close(){
        try {
            if (database != null && database.isOpen()) {
                // 关闭数据库
                database.close();
            }
            database = null;
            instance = null;
            initialized = false;
            Debug.i(TAG,"成功关闭数据库");
        } catch (Exception e) {
            Debug.e(TAG,"关闭数据库异常 "+e.getMessage(),e);
        }
    }

}
相关推荐
天天喝旺仔26 分钟前
MySQL 索引原理与慢查询优化实战:从 B+ 树到执行计划调优
数据库·sql·mysql·性能优化
liulilittle40 分钟前
Linux 下 select 测试函数
linux·服务器·网络·数据库·c++·select·c
DongQiShanRen1 小时前
玄龙(上):TICK 主循环——意识心跳怎么跳
linux·jvm·数据库·人工智能·数据挖掘·rust
数据库小学妹1 小时前
存算分离到底分离了什么?四条架构变化与选型判断
数据库·数据库架构·云原生数据库·缓存一致性·存算分离
FPGA小徐1 小时前
【一生一芯 / PA】异常响应机制:RISC-V 中 ecall → mtvec → mret 的完整代
开发语言·数据库·c#
m0_646429972 小时前
MySQL 初始化 SQL 中文乱码问题总结
数据库·sql·mysql
实战派K8S&DB2 小时前
TDSQL 核心模块与进程体系
运维·数据库·分布式·sql·mysql
FfHUCisI2 小时前
Go 性能分析工具 pprof:CPU、Heap 与 Goroutine 实战
数据库·golang
仍然.2 小时前
Redis---分布式锁
数据库·redis·分布式
ly76892 小时前
MongoDB 副本集选举风暴排查:从心跳超时到 Journal 刷盘阻塞
数据库·mongodb·php·mongodb 副本集·选举风暴·journal 刷盘·writeconcern