【发布时间】:2020-01-14 05:33:50
【问题描述】:
我正在使用 http 客户端从 Google Cloud Storage 读取一个可能很大的 CSV 文件。获得 CSV 文件后,我需要将其上传到另一个存储桶,并将数据加载到 BigQuery 表中。不幸的是,我正在下载的文件以 UTF-16 编码,BigQuery 仅支持 UTF-8。我需要一种将数据从 UTF-16 转换为 UTF-8 的方法。我知道我可以简单地将 http 响应输入流中的数据读取为 UTF-16,然后将其以 UTF-8 格式写入新的输入流,如下所示:
byte[] data = IOUtils.toByteArray(response.getEntity().getContent());
String csv = new String(data, StandardCharsets.UTF_8);
ByteArrayInputStream inputStream = new ByteArrayInputStream(csv.getBytes(StandardCharsets.UTF_8));
但是,鉴于 CSV 文件没有最大大小并且有可能非常大,我想尽可能避免将其读入内存。我需要这个过程的最终产品是一个 InputStream 以免破坏接口的合同。
我曾考虑使用 BufferedReader 一次读取一行输入流并转换编码,但我不确定一旦将其转换为新的输入流是否更有效。
有没有办法以一种内存高效的方式将输入流中的 UTF-16 内容转换为 UTF-8 内容?
【问题讨论】:
-
使用
IOUtils.copy(InputStream, Writer, Charset)。您可以将数据从输入流重定向到输出流 -
@maklas 感谢您的建议,但正如我所说,我需要将此过程的输出作为输入流,而不是写入器/输出流。
-
@Ben_Green。好的,明白了。您需要将字节解码为 utf16 字符,然后将它们编码为 utf8。那么这可能会奏效。双重包装输入流。
java InputStreamReader utf16Reader = new InputStreamReader(is, StandardCharsets.UTF_16); ReaderInputStream utf8IS = new ReaderInputStream(utf16Reader, StandardCharsets.UTF_8); -
@maklas 看起来不错。我假设 InputStreamReader 不会将输入流读入内存?如果您提出答案,我会投票赞成:)
-
@Ben_Green。当然可以。否则它将如何解码和编码。但它不会读取整个流并将其放入字符串中。它可能只是读取 8 kb 的小块,在一个 while 循环中处理每个块。因此它不会将所有数据加载到您的内存中。你的内存和垃圾收集器会很高兴。
标签: java character-encoding inputstream