如何将房间数据库导出为.CSV

iqxoj9l9  于 2023-01-15  发布在  其他
关注(0)|答案(2)|浏览(144)

我如何将我的房间数据库导出到一个.CSV文件。我想将它保存到设备存储。我搜索了所有内容,没有合适的答案。我希望有一种方法可以做到这一点。

6ioyuze2

6ioyuze21#

不能只将数据库另存为CSV。但是,如果数据库已设置完全检查点,则它只是一个文件。如果未设置完全检查点,则它将是三个文件(除非已禁用预写式事件记录)。
数据库本身由多个部分组成,包括文件头(文件的前100个字节)和用于各个组件的数据块。这些数据块中的大部分依赖于模式(表),也有系统表

  • sqlite_master是保存模式的表
  • 如果autogenerate = true用于整数类型主键,则还有sqlite_sequence表
  • 房间本身有一个room_master_table,其中房间存储了一个散列值,这个散列值与基于房间预期模式的编译散列值进行比较。

将所有数据保存为CSV将是复杂的(而且不必要,因为您可以只复制数据库文件)。
如果你想要的是应用数据的CSV格式,那么这将取决于表格。如果你是一个单一的表格,那么将数据提取为CSV格式将相对简单,但如果数据包含逗号,则可能会很复杂。
如果有多个表,则必须区分表的数据。
同样,如果只是保护数据,最简单的方法是复制文件。
然而,作为基于以下内容的示例:
具有3个表(系统表除外)的数据库

  • PostDataLocal(有关列,请参见下文)
  • 组数据本地
  • 管理数据本地
    • 已针对示例修改了现有答案 *

然后:
@Dao注解接口(即AllDao)中的以下内容:-

@Query("SELECT postId||','||content FROM postDataLocal")
fun getPostDataLocalCSV(): List<String>
@Query("SELECT groupPostIdMap||','||groupId||','||groupName FROM groupDataLocal")
fun getGroupDataLocalCSV(): List<String>
@Query("SELECT adminGroupIdMap||','||userId||','||adminName||','||avatar FROM adminDataLocal")
fun getAdminDataLocalCSV(): List<String>

以及以下函数,其中dao是之前示例化的AllDao示例:-

private fun createCSV() {

    val sb = StringBuilder()
    var afterFirst = false
    sb.append("{POSTDATALOCAL}")
    for (s in dao.getPostDataLocalCSV()) {
        if(afterFirst) sb.append(",")
        afterFirst = true
        sb.append(s)
    }
    afterFirst = false
    sb.append("{GROUPDATALOCAL}")
    for (s in dao.getGroupDataLocalCSV()) {
        if (afterFirst) sb.append(",")
        afterFirst = true
        sb.append(s)
    }
    afterFirst = false
    sb.append("{ADMINDATALOCAL}")
    for (s in dao.getAdminDataLocalCSV()) {
        if ((afterFirst)) sb.append(",")
        afterFirst = true
        sb.append(s)
    }
    Log.d("CSV_DATA","CSV is :-\n\t$sb")

}

然后在一个活动中(其中dao已经示例化)执行以下操作:

createCSV()

然后,当数据库包含以下数据(通过应用程序检查提取)时:-
本地发布数据

组数据本地

管理数据本地

写入日志的结果(可以写入文件而不是日志)为:-

D/CSV_DATA: CSV is :-
        {POSTDATALOCAL}1,Post001,2,Post002,3,Post003{GROUPDATALOCAL}1,1,Group001 (Post001),1,2,Group002 (Post001),1,3,Group003 (Post001),2,4,Group004 (Post002),2,5,Group005 (Post002),3,6,Group006 (Post003){ADMINDATALOCAL}1,1,Admin001,admin001.gif,1,2,Admin002,admin002.gif,1,3,Admin003,admin003.gif,2,4,Admin004,admin004.gif,2,5,Admin005,admin005.gif,3,6,Admin006,admin006.gif,4,7,Admin007,admin007.gif,5,8,Admin008,admin008.gif,6,9,Admin009,admin009.gif,6,10,Admin010,admin010.gif
  • 请注意如何包含标头以区分表
  • 当然,我们没有考虑在数据中包含逗号 (以上只是说明原则上您可以相对容易地生成数据的CSV表示)
    • 其他**

下面是一个自动化程度更高的版本,您不需要创建@Query注解函数,而是询问sqlite_master来提取表,并使用table_info杂注来确定列,从而构建相应的SQL。
因此,它应满足任何房间数据库。
它还允许用逗号指示符替换数据中的逗号,然后在处理CSV时可以替换逗号。
支持(次要/主要调用)功能为:

private fun getTableColumnNames(tableName: String, suppDB: SupportSQLiteDatabase): List<String> {
    val rv = arrayListOf<String>()
    val csr = suppDB.query("SELECT name FROM pragma_table_info('${tableName}')",null)
    while (csr.moveToNext()) {
        rv.add(csr.getString(0))
    }
    csr.close()
    return rv.toList()
}

主要功能:

private fun AutoCreateCSV(): String {
    val replaceCommaInData = "{COMMA}" /* commas in the data will be replaced by this */
    val rv = StringBuilder()
    val sql = StringBuilder()
    var afterFirstTable = false
    var afterFirstColumn = false
    var afterFirstRow = false
    val suppDb = db.getOpenHelper().writableDatabase
    var currentTableName: String = ""
    val csr = db.query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE('sqlite_%') AND name NOT LIKE('room_%') AND name NOT LIKE('android_%')", null)
    while (csr.moveToNext()) {
        sql.clear()
        sql.append("SELECT ")
        currentTableName = csr.getString(0)
        if (afterFirstTable) rv.append(",")
        afterFirstTable = true
        afterFirstColumn = false
        rv.append("{$currentTableName},")
        for (columnName in getTableColumnNames(currentTableName,suppDb)) {
            if (afterFirstColumn) sql.append("||','||")
            afterFirstColumn = true
            sql.append("replace(`$columnName`,',','$replaceCommaInData')")
        }
        sql.append(" FROM `${currentTableName}`")
        val csr2 = db.query(sql.toString(),null)
        afterFirstRow = false
        while (csr2.moveToNext()) {
            if (afterFirstRow) rv.append(",")
            afterFirstRow = true
            rv.append(csr2.getString(0))
        }
        csr2.close()
    }
    csr.close()
    return rv.toString()
}

使用相同的数据,并且作为返回字符串的主函数,以下代码Log.d("CSV_DATA2",AutoCreateCSV())将产生:-

D/CSV_DATA2: {PostDataLocal},1,Post001,2,Post002,3,Post003,{GroupDataLocal},1,1,Group001 (Post001),1,2,Group002 (Post001),1,3,Group003 (Post001),2,4,Group004 (Post002),2,5,Group005 (Post002),3,6,Group006 (Post003),{AdminDataLocal},1,1,Admin001,admin001.gif,1,2,Admin002,admin002.gif,1,3,Admin003,admin003.gif,2,4,Admin004,admin004.gif,2,5,Admin005,admin005.gif,3,6,Admin006,admin006.gif,4,7,Admin007,admin007.gif,5,8,Admin008,admin008.gif,6,9,Admin009,admin009.gif,6,10,Admin010,admin010.gif

并且如果数据包括逗号,例如Post001被改变为值Post001, <<note the comma in the data>>
然后:

D/CSV_DATA2: {PostDataLocal},1,Post001{COMMA} <<note the comma in the data>>,2,Post002,3 ....
  • 这个附加的解决方案也修复了第一个中的一个小错误,其中在报头和数据之间省略了一些分隔逗号。
uelo1irk

uelo1irk2#

从房间中获取所有数据作为列表并使用此库https://github.com/doyaaaaaken/kotlin-csv
效果很好,这是我的用法

private fun exportDatabaseToCSVFile(context: Context, list: List<AppModel>) {
    val csvFile = generateFile(context, getFileName())
    if (csvFile != null) {

        exportDirectorsToCSVFile(csvFile, list)

    } else {
        //
    }
}

private fun generateFile(context: Context, fileName: String): File? {
    val csvFile = File(context.filesDir, fileName)
    csvFile.createNewFile()

    return if (csvFile.exists()) {
        csvFile
    } else {
        null
    }
}

private fun getFileName(): String = "temp.csv"

fun exportDirectorsToCSVFile(csvFile: File, list: List<AppModel>) {
    csvWriter().open(csvFile, append = false) {
        // Header
        writeRow(listOf("row1", "row2", "row3"))
        list.forEachIndexed { index, appModel ->
            writeRow(listOf(getRow1, getRow2, getRow3))
        }
        shareCsvFile(csvFile)
    }
}

private fun shareCsvFile(csvFile: File) {
    // share your file, don't forget adding provider in your Manifest
}

相关问题