You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请求Kotlin实现PDF文件存入SQLite数据库(BLOB方式)的示例代码

在Android Kotlin中实现PDF文件存入SQLite数据库(BLOB方式)

一、配置Room数据库(推荐使用,替代原生SQLite)

首先添加Room依赖到build.gradle(Module级别):

dependencies {
    def room_version = "2.5.0"
    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
    // Kotlin扩展支持
    implementation "androidx.room:room-ktx:$room_version"
}

1. 创建实体类(对应数据库表)

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "pdf_files")
data class PdfFile(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val fileName: String, // 用于区分不同PDF文件
    val pdfBlob: ByteArray // 存储PDF的字节数组
) {
    // 重写equals和hashCode,解决ByteArray默认比较引用的问题
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false
        other as PdfFile
        if (id != other.id) return false
        if (fileName != other.fileName) return false
        if (!pdfBlob.contentEquals(other.pdfBlob)) return false
        return true
    }

    override fun hashCode(): Int {
        var result = id
        result = 31 * result + fileName.hashCode()
        result = 31 * result + pdfBlob.contentHashCode()
        return result
    }
}

2. 创建Dao接口

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query

@Dao
interface PdfFileDao {
    @Insert
    suspend fun insertPdf(pdfFile: PdfFile)

    @Query("SELECT * FROM pdf_files WHERE fileName = :name")
    suspend fun getPdfByName(name: String): PdfFile?
}

3. 创建数据库实例

import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import android.content.Context

@Database(entities = [PdfFile::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun pdfFileDao(): PdfFileDao

    companion object {
        // 单例模式避免重复创建数据库实例
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getDatabase(context: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "app_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

二、将Assets中的PDF转为字节数组

把你的PDF文件放在src/main/assets目录下,用以下方法读取为ByteArray:

import android.content.Context
import java.io.ByteArrayOutputStream
import java.io.IOException

fun getPdfFromAssets(context: Context, fileName: String): ByteArray? {
    return try {
        context.assets.open(fileName).use { inputStream ->
            ByteArrayOutputStream().use { outputStream ->
                val buffer = ByteArray(1024)
                var length: Int
                while (inputStream.read(buffer).also { length = it } != -1) {
                    outputStream.write(buffer, 0, length)
                }
                outputStream.toByteArray()
            }
        }
    } catch (e: IOException) {
        e.printStackTrace()
        null
    }
}

三、插入PDF到数据库

在协程中执行数据库操作(避免主线程阻塞):

import android.content.Context
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

fun insertPdfIntoDatabase(context: Context, fileName: String) {
    val pdfBytes = getPdfFromAssets(context, fileName) ?: return
    val pdfFile = PdfFile(fileName = fileName, pdfBlob = pdfBytes)

    GlobalScope.launch(Dispatchers.IO) {
        val db = AppDatabase.getDatabase(context)
        db.pdfFileDao().insertPdf(pdfFile)
    }
}

四、从数据库读取PDF并使用

读取后可写入临时文件,再用第三方PDFView打开(以com.github.barteksc:android-pdf-viewer为例):

import android.content.Context
import android.os.Environment
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileOutputStream

fun readPdfFromDatabase(context: Context, fileName: String, onPdfReady: (File?) -> Unit) {
    GlobalScope.launch(Dispatchers.IO) {
        val db = AppDatabase.getDatabase(context)
        val pdfFile = db.pdfFileDao().getPdfByName(fileName) ?: run {
            withContext(Dispatchers.Main) { onPdfReady(null) }
            return@launch
        }

        // 创建临时文件存储读取到的PDF
        val tempFile = File(context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), fileName)
        try {
            FileOutputStream(tempFile).use { outputStream ->
                outputStream.write(pdfFile.pdfBlob)
            }
            withContext(Dispatchers.Main) { onPdfReady(tempFile) }
        } catch (e: Exception) {
            e.printStackTrace()
            withContext(Dispatchers.Main) { onPdfReady(null) }
        }
    }
}

五、注意事项

  • 文件大小限制:SQLite支持最大1GB的BLOB,但大体积PDF会显著降低数据库性能,建议只存储几MB以内的小文件。
  • 主线程操作:所有数据库操作必须在子线程执行,这里用协程Dispatchers.IO处理,避免ANR。
  • APK体积:将PDF打包进APK会增加安装包大小,若存在多个大文件,建议权衡是否改用在线下载+本地存储路径的方案。

内容的提问来源于stack exchange,提问作者Whitt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 13:53:14