【问题标题】:Exporting Room Database to csv file in android在android中将房间数据库导出到csv文件
【发布时间】:2018-12-05 21:37:26
【问题描述】:

有很多教程可用于将 SQLite 数据库导出到 csv 文件,但从房间数据库导出的内容还不够。

使用 sqlite 导出引用 Exporting SQLite Database to csv file in android 手动解析行的每一列以获得空间。以下是我的代码:

     @Dao
     interface CategoryDao {
         @Query("SELECT * FROM Category")
         fun getAllCategory(): List<Category>
     }

//   Export csv logic

      val categoryList = categoryDao.getAllCategory()
      val csvWrite = CSVWriter(FileWriter(file))

      for (item in categoryList) {
         val arrStr = arrayOf<String>(item.categoryId, item.categoryName)
         csvWrite.writeNext(arrStr)
      }

还有其他导出csv的方法吗?即使在房间里也没有实用地获取表的列名,因此无法为所有表创建动态的通用逻辑。

【问题讨论】:

  • 房间数据库是sqlite数据库——没有区别
  • 您可以使用 Jackson CSV 库将 Room 类映射到文件中

标签: android csv kotlin export-to-csv android-room


【解决方案1】:

试试这个
从 Cursor 中获取 Column 数据

@Query("SELECT * FROM Category")
Cursor getAllCategory();

【讨论】:

    【解决方案2】:

    要将房间数据库数据导出到mydb.sqlite 文件并存储到外部存储中,请按照以下步骤操作。

      fun exportDatabase(){
          val sd = Environment.getExternalStorageDirectory()
    
          // Get the Room database storage path using SupportSQLiteOpenHelper 
          AppDatabase.getDatabase(applicationContext)!!.openHelper.writableDatabase.path
    
                if (sd.canWrite()) {
                    val currentDBPath = AppDatabase.getDatabase(applicationContext)!!.openHelper.writableDatabase.path
                    val backupDBPath = "mydb.sqlite"      //you can modify the file type you need to export
                    val currentDB = File(currentDBPath)
                    val backupDB = File(sd, backupDBPath)
                    if (currentDB.exists()) {
                        try {
                            val src = FileInputStream(currentDB).channel
                            val dst = FileOutputStream(backupDB).channel
                            dst.transferFrom(src, 0, src.size())
                            src.close()
                            dst.close()
                        } catch (e: IOException) {
                            e.printStackTrace()
                        }
                    }
                }
           }
    

    【讨论】:

      【解决方案3】:

      我尝试通过两种方式迭代大型 Room 数据库:

      1- 获取 Cursor 并对其进行迭代:

      import android.database.Cursor
      ...
      @Query("SELECT * FROM Category")
      fun getAllCategory(): Cursor<Category>
      ...
      val success = cursor.moveToFirst()
      if (success) {
           while (!cursor.isAfterLast) {
               // Process items
               cursor.moveToNext()
           }
      } else {
          // Empty
      }
      cursor.close()
      

      2- 使用PagedList 一次获取pageSize 数量的项目并进行处理。然后查询另一个页面并处理:

      @Query("SELECT * FROM Category")
      fun getAllCategory(): DataSource.Factory<Int, Category>
      
      // Here i will return Flowable. You can return LiveData with 'LivePagedListBuilder'
      fun getCategories(pageSize: Int): Flowable<PagedList<Category>> {
              val config = PagedList.Config.Builder()
                      .setPageSize(pageSize)
                      .setPrefetchDistance(pageSize / 4)
                      .setEnablePlaceholders(true)
                      .setInitialLoadSizeHint(pageSize)
                      .build()
              return RxPagedListBuilder(categoryDao.getAllCategory(), config)
                      .buildFlowable(BackpressureStrategy.BUFFER)
      }
      

      现在上面的getCategories() 函数将在FlowableLiveData 内返回pagedList。由于我们设置了setEnablePlaceholders(true)pagedList.size 将显示整个大小,即使它不在内存中。因此,如果pageSize 为 50,并且所有数据大小为 1000,pagedList.size 将返回 1000,但其中大部分为空。查询下一页并处理:

      // Callback is triggered when next page is loaded
      pagedList.addWeakCallback(pagedList.snapshot(), object : PagedList.Callback() {
          override fun onChanged(position: Int, count: Int) {
              for (index in position until (position + count)) {
                  if (index == (position + count - 1)) {
                      if (index < (pagedList.size - 1)) 
                          pagedList.loadAround(index + 1)
                      else{ 
                          // Last item is processed.
                      }
                  } else
                      processCurrentValue(index, pagedList[index]!!)
              }
          }
          override fun onInserted(position: Int, count: Int) {
              // You better not change database while iterating over it 
          }    
          override fun onRemoved(position: Int, count: Int) {
              // You better not change database while iterating over it
          }
      })
      
      // Start to iterate and query next page when item is null.
      for (index in 0 until pagedList.size) {
           if (pagedList[index] != null) {
                  processCurrentValue(index, pagedList[index]!!)
           } else {
                  // Query next page
                  pagedList.loadAround(index)
                  break
           }
      }
      

      结论:在PagedList 方法中,您可以一次获取数千行并进行处理,而在Cursor 方法中,您可以逐行迭代。当pageSize > 3000时我发现PagedList不稳定。它有时不返回页面。所以我使用了Cursor。在 Android 8 手机上使用这两种方法迭代(和处理)900k 行大约需要 5 分钟。

      【讨论】:

      • 问题是关于导出数据库而不是关于如何使用分页库!
      • 它是关于通过迭代表的overvrows来导出数据库。因为您可能会在导出时转换数据。导出不仅意味着转储数据库并从中创建包含所有内容的文件
      猜你喜欢
      • 1970-01-01
      • 2023-01-13
      • 2015-09-30
      • 2022-08-02
      • 2013-09-10
      • 2015-03-02
      • 1970-01-01
      • 2018-08-29
      • 2012-12-22
      相关资源
      最近更新 更多