如何将Room数据库导出为.CSV文件

3
我该如何将我的Room数据库导出到.CSV文件并保存到设备存储器中?我已经搜索了很多,但没有合适的答案。希望有一种方法可以实现这个功能。
2个回答

6
无法直接将数据库保存为CSV文件。但是,如果数据库已被完全检查点,则它只是一个文件。如果未被完全检查点,则它会有三个文件(除非已禁用预写式日志记录)。
数据库本身由各种部分组成,包括标题(文件的前100字节),以及各个组件的数据块。大多数这些都取决于模式(表),还有一些系统表:
- `sqlite_master`是保存模式的表。 - 如果对于整数类型的主键使用了`autogenerate = true`,则还会有`sqlite_sequence`表。 - Room本身有`room_master_table`,在其中Room存储哈希值,并与基于Room期望的模式编译的哈希进行比较。
要将所有这些数据保存为CSV将很复杂(而且是不必要的,因为您可以只复制数据库文件)。如果您想要的是应用程序数据的CSV,则这将取决于表。如果只有一个表,则提取数据作为CSV将相对简单,但如果数据包含逗号,则可能会变得复杂。如果有多个表,则必须区分表的数据。
同样的,如果只是想保护数据,那么最简单的方法是复制文件。然而,以下是一个示例:一个除系统表外有3个表(请参见下面的列)的数据库。
在@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() 

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

PostDataLocal

  • enter image description here

GroupDataLocal

  • enter image description here

AdminDataLocal

  • enter image description here

将结果写入日志(也可以写入文件而不是日志)的内容为:

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 pragma来确定列,构建相应的SQL。

因此,它应该适用于任何Room数据库。

它还允许将数据中的逗号替换为逗号指示符,然后可以在处理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, <<注意数据中的逗号>>

那么:

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

1
这正是我需要的答案,非常有帮助,愿上帝保佑你!! - Faris Rizvanović

0

从Room中以列表形式获取所有数据,并使用此库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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接