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);
        }
    }

}
相关推荐
TDengine (老段)9 小时前
TDengine 压缩编码机制 — 双层压缩架构与类型特化算法
大数据·数据库·物联网·算法·时序数据库·tdengine·涛思数据
苏渡苇10 小时前
Redis 持久化——RDB 快照 vs AOF 日志
数据库·redis·缓存·redis持久化·aof vs rdb
l1t10 小时前
DeepSeek总结的使用 PEG 实现运行时可扩展的 SQL 解析器
数据库·sql
这个DBA有点耶11 小时前
COUNT进阶(续):超大表去重计数的极致优化
数据库·架构·代码规范
爱喝水的鱼丶11 小时前
SAP-ABAP:SAP 简单报表输出开发系列(共6篇) 第四篇:SAP 报表异常处理机制:数据校验与消息提示规范落地
开发语言·数据库·学习·算法·sap·abap
_1_711 小时前
SQL SERVER闪退问题解决
数据库·sqlserver
ZengLiangYi11 小时前
sql.js WASM 深度解析
javascript·数据库·后端
一 乐11 小时前
人口老龄化社区服务与管理平台|基于springboot+vue的人口老龄化社区服务与管理平台(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·人口老龄化社区服务与管理平台
梓䈑11 小时前
【MySQL】表的操作(数据表的创建、查看 和 修改)
数据库·mysql
小碗羊肉12 小时前
【Redis | 第六篇】Redisson
数据库·redis·缓存