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

}
相关推荐
皮皮学姐分享-ppx4 分钟前
上市公司数字技术风险暴露数据(2010-2024)|《经济研究》同款大模型测算
大数据·网络·数据库·人工智能·chatgpt·制造
CLX05054 分钟前
如何在 WordPress AMP 网站中为特定模板禁用 AMP 渲染
jvm·数据库·python
神明9318 分钟前
如何实现SQL动态字段选择查询_利用反射或动态拼接字符串
jvm·数据库·python
m0_7335654618 分钟前
golang如何实现RabbitMQ死信队列_golang RabbitMQ死信队列实现教程
jvm·数据库·python
weixin_4440129323 分钟前
CSS定位如何实现模态框垂直居中_使用负边距或transform
jvm·数据库·python
2301_7838486528 分钟前
Go 中实现高效图最大团划分的实践与边界分析
jvm·数据库·python
2401_8844541529 分钟前
C#怎么实现Socket心跳包 C#如何在TCP Socket通信中设计心跳机制检测连接状态【网络】
jvm·数据库·python
Jetev41 分钟前
不同品牌SSD对HTML函数工具加载速度影响大吗_存储测试汇总【汇总】
jvm·数据库·python
SelectDB技术团队41 分钟前
时间序列近邻关联性能实测:Doris ASOF JOIN 领先 ClickHouse、DuckDB
数据库·人工智能·selectdb
Traving Yu1 小时前
向量数据库Milvus
数据库·人工智能·milvus