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

Kotlin安卓:SQLite导出数据至TXT文件为空问题求助

联系人APP导出/导入TXT功能修复方案

问题分析

当前导出功能存在两个核心问题:

  • 数据格式错误:dataToWriteInFile()直接调用getContactsList().toString(),会生成带方括号、逗号分隔的List字符串,不符合每行一个联系人、分号分隔字段的要求。
  • 原文件写入逻辑错误:最初代码尝试用File处理Content URI,违反Android文件系统规范;更新后的写入逻辑方向正确,但数据生成错误导致文件内容异常。

修复步骤

1. 修正数据生成逻辑

修改dataToWriteInFile()方法,遍历联系人列表,将每个联系人的格式化字符串(已通过ContactModelClass.toString()实现分号分隔)逐行写入StringBuilder:

private fun dataToWriteInFile(): String {
    val stringBuilder = StringBuilder()
    getContactsList().forEach { contact ->
        stringBuilder.appendLine(contact.toString())
    }
    return stringBuilder.toString()
}

2. 优化文件写入逻辑(确保稳定性)

简化更新后的写入逻辑,去除冗余判断,利用Kotlin的use函数自动关闭流:

private val createFile = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
        result.data?.data?.let { uri ->
            try {
                contentResolver.openOutputStream(uri)?.use { outputStream ->
                    outputStream.writer().use { writer ->
                        writer.write(dataToWriteInFile())
                    }
                }
            } catch (e: IOException) {
                e.printStackTrace()
                // 可添加Toast提示用户导出失败
            }
        }
    }
}

3. 实现TXT导入功能

添加导入逻辑,调用文件选择器读取TXT文件,解析每行内容并插入SQLite:

3.1 注册文件选择器

在ContactListActivity中添加导入用的ActivityResultContract:

private val pickFile = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
        result.data?.data?.let { uri ->
            try {
                contentResolver.openInputStream(uri)?.use { inputStream ->
                    inputStream.bufferedReader().useLines { lines ->
                        val sqliteHelper = SQLiteHelper(this)
                        // 可选:导入前清空现有数据,根据需求调整
                        // sqliteHelper.deleteContactsTable()
                        lines.forEach { line ->
                            val fields = line.split(";")
                            if (fields.size == 9) { // 校验字段数量匹配
                                val contact = ContactModelClass(
                                    id = fields[0].toInt(),
                                    name = fields[1],
                                    surname = fields[2],
                                    dateOfBirth = fields[3],
                                    phoneNumber = fields[4],
                                    email = fields[5],
                                    address = fields[6],
                                    city = fields[7],
                                    notes = fields[8]
                                )
                                sqliteHelper.insertContact(contact)
                            }
                        }
                        // 导入完成后刷新RecyclerView
                        setupListOfDataIntoRecyclerView()
                    }
                }
            } catch (e: IOException) {
                e.printStackTrace()
                // Toast提示导入失败
            } catch (e: NumberFormatException) {
                e.printStackTrace()
                // Toast提示文件格式错误
            }
        }
    }
}

3.2 添加导入按钮点击事件

在onCreate中绑定导入按钮(需先在布局中添加对应按钮):

// 假设布局中按钮id为importDataButton
val importDataButton = findViewById<Button>(R.id.importDataButton)
importDataButton.setOnClickListener {
    val pickFileIntent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "text/plain"
    }
    pickFile.launch(pickFileIntent)
}

关键说明

  • ContactModelClass的toString()方法已正确实现字段分号分隔,无需修改。
  • 导出/导入均使用Android Content URI机制,符合现代Android文件访问规范,可直接访问下载文件夹等外部存储位置。
  • 导入时添加了字段校验和异常捕获,避免因文件格式错误导致崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 23:22:33