在 Android Google Sheets 应用程序上预览 CSV 文件时出现编码问题

问题描述 投票:0回答:1

我目前正在 Android 应用程序中开发一项新功能,允许用户将数据导出为 CSV 文件。

导出过程在后端管理。在应用程序端,我们下载二进制文件,暂时保存,然后使用 ACTION_VIEW 意图进行预览。这允许用户选择他们喜欢的应用程序来查看和共享文件。

但是,我遇到了编码问题,但仅限于使用表格应用程序时。在 PC、macOS 甚至 Google Sheets Web 上打开文件可以按预期工作。

分享组件 Google 表格应用预览
share component google sheets preview
在 Android 上

我们获取文档如下:

...
override suspend fun getDocument(file: File): File {
    val body = http.execute(
        call = { service.getDocument(...) },
        onError = { ... },
    )
    withContext(dispatchers.io) {
        file.writeBytes(body.source().readByteArray())
    }
    return file
}
...

然后我们使用意图打开它:

...
fun createFileIntent(context: Context, file: File, mediaType: MimeType? = null): Intent {
    val contentUri = file.getContentUri(context)
    val type = mediaType?.value ?: contentUri.getMimeType(context)
    val intent = Intent(ACTION_VIEW)

    intent.setDataAndType(contentUri, type)
    intent.flags = FLAG_GRANT_READ_URI_PERMISSION
    return intent
}
...
private fun showCsv(file: File) {
    val intent = createFileIntent(requireContext(), file)
    startActivity(intent)
}
在后台
Response.ok(outputStream(activitiesCSV))
    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"activities.csv\"")
    .header(HttpHeaders.CONTENT_TYPE, "text/csv; charset=utf-8")
    .build()
private StreamingOutput outputStream(byte[] bytes) {
    final byte[] bom = new byte[] { (byte) 239, (byte) 187, (byte) 191 };  //UTF-8 BOM
    return outputStream -> {
        outputStream.write(bom);
        outputStream.write(bytes);
        outputStream.flush();
    };
}

activitiesCSV
是从数据库检索的
byte[]
。 如果我不添加
UTF-8-BOM
,在 MS Excel 中打开 csv 时将无法识别特殊字符,但这里我们在 Google Sheets 应用程序上遇到了问题。

android android-intent character-encoding export-to-csv
1个回答
0
投票

我们通过删除后端的 BOM 标头并在 Android 端添加以下代码解决了该问题,这确保了从 UTF-8 到 ISO_8859_1 (Latin 1) 的转换。

override suspend fun getDocument(file: File): File {
    val body = http.execute(
        call = { service.getDocument(...) },
        onError = { ... },
    )
    withContext(dispatchers.io) {
        val sourceByteArray = body.source().readByteArray()
        val byteArrayToWrite = when (fileType) {
            CSV ->
                sourceByteArray
                    .toString(body.contentType()?.charset() ?: UTF_8)
                    .toByteArray(ISO_8859_1)
            else -> sourceByteArray
        }
        file.writeBytes(byteArrayToWrite)
    }
    return file
}
© www.soinside.com 2019 - 2024. All rights reserved.