【问题标题】:Convert byte-stream to character-stream in Java在Java中将字节流转换为字符流
【发布时间】:2011-06-12 21:43:50
【问题描述】:

是否有一个类可以通过指定编码来创建它,将字节流输入其中并从中获取字符流?主要的一点是我想通过不在内存中同时同时拥有整个字节流数据和整个字符流数据来节省内存。

类似:

Something s = new Something("utf-8");
s.write(buffer, 0, buffer.length); // it converts the bytes directly to characters internally, so we don't store both
// ... several more s.write() calls
s.close(); // or not needed

String text = s.getString();
// or
char[] text = s.getCharArray();

Something 是什么?

【问题讨论】:

  • 您想从一个巨大的 byte[] 缓冲区开始并以一个巨大的 String 文本结束而不需要两个内存?如果是这样,算了,这是行不通的。以 byte[] 开头并返回 CharSequence(访问缓冲区)是可能的,但值得吗?

标签: java arrays encoding stream character


【解决方案1】:

实际上,标题“在 Java 中将字节流转换为字符流”与您的示例相矛盾,除了 数组 之外根本不使用流。我进一步假设您需要数组。

您肯定不能以 byte[] 开头并以 char[](或 String)结尾,而这两者都需要一段时间。不过也有一些可能性:

  • 如果您真的需要char[]:想法:将字节[] 写入文件并使用 FileReader 将其读取到数组中。这实际上不起作用,因为您事先不知道正确的数组长度。因此,使用 DataOutput 生成所有字符并将其写入文件,然后使用 DataInput 将所有字符读回数组中。

  • 如果您真的需要String:如上所述创建char[],并使用反射和setAccessibe(true) 调用包私有ctor String(int offset, int count, char value[])

  • 如果 CharSequence 足够:创建一个 MyCharSequence 类来保存字节 []。一个极其缓慢的解决方案是通过从头开始转换部分字节 [] 直到获得 index+1 字符来实现其方法 charAt(index)。即时丢弃所有这些并保留最后一个。需要这种愚蠢的方法,因为使用utf8 您不知道单个字符对应多少字节。您可以在开始时执行一次并记住每个字符的第一个字节的位置。这更加愚蠢,因为这些位置需要更多内存。幸运的是,存在一个简单的时空权衡,例如,记住每个第 16 个字符的第一个字节的位置。

我所有的建议都有点奇怪,但我相信,不能做得更好。这可能是一个有趣的家庭作业,我不会去做。

【讨论】:

    【解决方案2】:

    您的示例代码似乎没有表明需要字符流。如果是这样,String 已经可以处理您想要的所有内容。假设String s 包含数据,

    char[] chars = s.toCharArray();
    byte[] bytes = s.getBytes("utf-8");
    

    然后问题归结为如何从字节流中获取字节到String,您可以使用ByteArrayOutputStream,如下所示:

    ByteArrayOutputSteam os = new ByteArrayOutputSteam();
    os.write(buffer, 0, buffer.length); // it just stores the bytes, doesn't convert yet.
    // several more os.write() calls
    s = os.toString("utf-8"); // now it converts the full buffer to a string in the specified encoding.
    

    如果您真的想要具有字节输入流和字符输出流的东西,那么没有内置的。

    【讨论】:

      【解决方案3】:

      您可以使用CharsetDecoder 模拟它。类似于

          CharsetDecoder decoder = Charset.forName(encoding).newDecoder();
          CharBuffer cb = CharBuffer.allocate(100);
          decoder.decode(ByteBuffer.wrap(buffer1), cb, false);
          decoder.decode(ByteBuffer.wrap(buffer2), cb, false);
          ...
          decoder.decode(ByteBuffer.wrap(bufferN), cb, true);
          cb.position(0);
          return cb.toString();
      

      (是的,我知道这会溢出您的 CharBuffer ——您可能希望将内容复制到 StringBuilder 中。)

      【讨论】:

      • 如果您确实有一个InputStream 而不仅仅是一系列byte[] 缓冲区,那么InputStreamReader 是正确的选择...
      【解决方案4】:

      您在寻找ByteArrayInputStream 吗?然后,您可以将其包装在 InputStreamReader 中并从原始字节数组中读取字符。

      ByteArrayInputStream 允许您从字节数组“流式传输”。如果将其包装在 InputStreamReader 中,则可以读取字符。 InputStreamReader 让您指定字符编码。

      如果你想直接从字节的输入源出发,那么你可以构造适当的InputStream类(例如FileInputStream),然后将其包装在@ 987654328@.

      【讨论】:

      • 嗯,没错,但是在内存中会有一段时间字节数组数据和字符数组数据同时存在。是否有可能在输入字节流时,Something 将字节流转换为字符数组? (我们丢失了原始字节流数据,但我们只需要那个字符数组输出)。我会在这个问题上澄清这一点。
      • 如果您将文件作为 Stream 打开,然后将 Reader 包裹在 Stream 实例周围,那么唯一需要担心的是附带缓冲。您不会用同一事物的两个版本来填满内存。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-24
      • 1970-01-01
      • 2019-08-12
      • 1970-01-01
      • 2021-03-27
      • 1970-01-01
      相关资源
      最近更新 更多