【问题标题】:How to parse very large json array with Moshi in Android?如何在 Android 中使用 Moshi 解析非常大的 json 数组?
【发布时间】:2022-01-22 09:09:37
【问题描述】:

我有一个很大的json 文件,其中包含来自字典的特定语言的单词。该文件有超过 348 000 多个单词。每个对象都有不同的属性。

这是json 数组的示例:

[
...
{"id":"57414","form":"t'est","formNoAccent":"test","formUtf8General":"test","reverse":"tset","number":null,"description":"","noAccent":"0","consistentAccent":"1","frequency":"0.98","hyphenations":null,"pronunciations":null,"stopWord":"0","compound":"0","modelType":"N","modelNumber":"1","restriction":"","staleParadigm":"0","notes":"","hasApheresis":"0","hasApocope":"1","createDate":"1196798482","modDate":"1637245287"},
{"id":"57415","form":"ț'est","formNoAccent":"țest","formUtf8General":"țest","reverse":"tseț","number":null,"description":"","noAccent":"0","consistentAccent":"1","frequency":"0.93","hyphenations":null,"pronunciations":null,"stopWord":"0","compound":"0","modelType":"N","modelNumber":"24","restriction":"","staleParadigm":"0","notes":"","hasApheresis":"0","hasApocope":"1","createDate":"1196798482","modDate":"1637245213"},
...
]

我想在Room 中添加这些条目,并让它们保留在那里。我现在面临的问题是我没有做任何类似的事情,当我尝试使用Moshi 将所有内容转换为对象列表时,我得到了out of memory

解决方案是单独加载每个项目,但我认为这是不可能的。

到目前为止,它看起来像这样:

        val archive = context.assets.open("table_lexeme.zip")
        val destination = File.createTempFile("table_lexeme", ".zip")
        val jsonFile = File.createTempFile("lexeme", ".json")

        archive.use {
            destination.writeBytes(it.readBytes())
        }

        ZipFile(destination).use { zip ->
            zip.entries().asSequence().forEach { zipEntry ->
                if (zipEntry.name == "dex_table_lexeme.json") {
                    zip.getInputStream(zipEntry).use { inputStream ->
                        val bos = BufferedOutputStream(FileOutputStream(jsonFile))
                        val bytesIn = ByteArray(BUFFER_SIZE)
                        var read: Int
                        while (inputStream.read(bytesIn).also { read = it } != -1) {
                            bos.write(bytesIn, 0, read)
                        }
                        bos.close()
                    }
                }
            }
        }

        val jsonReader = JsonReader(InputStreamReader(jsonFile.inputStream(), Charsets.UTF_8))
        jsonReader.beginArray()

【问题讨论】:

  • “我想在 Room 中添加这些条目并让它们保留在那里”——因为这些数据被打包为资产,你为什么要搞乱 ZIP 文件和 JSON? Room 支持打包数据库作为资产,因此您可以发送实际的 SQLite 数据库而不是 JSON。与导入数十万行相比,为用户设置这将快得多
  • @CommonsWare 你知道我可以用什么工具来打包数据库吗?
  • 我会使用 Room 本身来创建空数据库。从那里,您有无数用于填充数据的 SQLite 选项。例如,我使用过 Ruby 脚本和 Kotlin 命令行程序。或者,有像 DB Browser for SQLite 这样的 GUI 工具。之后,您将数据库放入assets 并从那里滚动。请参阅gitlab.com/commonsguy/cw-room/-/tree/v0.9/PackagedFTS 了解使用打包数据库的示例应用程序(在this book,FWIW 中介绍)。
  • 我记得我为什么不这样做。我拥有的数据库在 Mysql/MariaDB 中,将我需要的表导出为 JSON 是我可以使用它的最准确的方式,而无需更改脚本以与 Sqlite3 兼容
  • 这不会阻止您在开发机器上使用该 JSON 创建 SQLite 数据库。

标签: android moshi


【解决方案1】:

字面解决方案是切换到流式 JSON 解析器,因此您的整个数据集不会立即加载到 RAM 中。 Android SDK 中的JsonReader 就是这样工作的,Gson 有流模式。我不记得 Moshi 提供过这个,但我最近没有寻找过那个。

现实的解决方案是不打包 JSON。即使您使用事务批处理(例如,在批处理中插入 100 行),导入它们也会很慢。您正在将数据打包为资产,因此最好(恕我直言)在您的开发机器上生成 SQLite 数据库并将其打包。 Room 内置支持从资产复制打包的数据库并将其放置在适当的位置以供使用。虽然您的数据库文件会很大,但复制它会比使用导入的数据动态创建它更快。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-23
    • 1970-01-01
    • 2021-04-24
    • 1970-01-01
    • 1970-01-01
    • 2018-11-24
    • 2017-03-17
    相关资源
    最近更新 更多