2013-06-23 45 views
3

我需要将一串字节转换为一行UTF-8字符。唯一对我来说很重要的角色是最后一个角色。这种转换应该在一个周期中进行,所以性能非常重要。一个简单的和低效的做法是:如何将字节流转换为UTF-8字符?

public class Foo { 
    private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
    void next(byte input) { 
    this.buffer.write(input); 
    String text = this.buffer.toString("UTF-8"); // this is time consuming 
    if (text.charAt(text.length() - 1) == THE_CHAR_WE_ARE_WAITING_FOR) { 
     System.out.println("hurray!"); 
     this.buffer.reset(); 
    } 
    } 
} 

字节数组转换为字符串发生在每一个输入字节,这一点,在我的理解,非常无效。是否有可能以某种方式来保留从前一个周期的字节到文本转换的结果?

+0

我在这里错过了一些东西。当UTF-8文本每个字符使用多个字节时,如何转换单个字节? –

+0

这就是为什么我需要执行此转换作业的'ByteArrayOutputStream' – yegor256

+0

为什么不使用InputStreamReader? – Clyde

回答

2

基于评论:

它的换行字符(0x0A)

next方法可以只检查:

if ((char)input == THE_CHAR_WE_ARE_WAITING_FOR) { 
    //whatever your logic is. 
} 

您不必做任何字符转换< 128.

0

将您的获取字节的代码包装在InputStream中并将其传递给InputStreamReader。

InputStreamReader isr = new InputStreamReader(new InputStream() { 
     @Override 
     public int read() throws IOException { 
      return xx();// wherever you get your data from. 
     } 
    }, "UTF-8"); 
    while(true) { 
     try { 
      if(isr.read() == THE_CHAR_WE_ARE_WAITING_FOR) 
       System.out.println("hurray!"); 
     } catch(IOException e) { 
      e.printStackTrace(); 
     } 
    } 
+0

查看我的问题的更新。我不能等待字节..他们从其他地方注入我的课程。换句话说,我不能留下来等待下一个字节,就像你的例子 – yegor256

+0

使用另一个线程来等待数据被注入。 – Clyde

+0

@ yegor256现在编辑它的问题与原始问题有根本的不同。编辑问题的两个选项是使用InputStreamReader和专用线程来等待数据,或者实现有状态的UTF-8解码器。 UTF-8序列的长度最大为4,长度可以通过检查第一个字节来确定。一旦检查完每个序列,就可以丢弃它,而不是像你的代码那样缓冲整个输入流(因为你意识到效率不高)。 – Clyde

2

您可以使用一个简单的类来跟踪字符,并且只在获得完整的UTF8序列时进行转换。下面是一个示例(与您可能要添加没有错误检查)

class UTF8Processor { 
    private byte[] buffer = new byte[6]; 
    private int count = 0; 

    public String processByte(byte nextByte) throws UnsupportedEncodingException { 
     buffer[count++] = nextByte; 
     if(count == expectedBytes()) 
     { 
      String result = new String(buffer, 0, count, "UTF-8"); 
      count = 0; 
      return result; 
     } 
     return null; 
    } 

    private int expectedBytes() { 
     int num = buffer[0] & 255; 
     if(num < 0x80) return 1; 
     if(num < 0xe0) return 2; 
     if(num < 0xf0) return 3; 
     if(num < 0xf8) return 4; 
     return 5; 
    } 
} 

class Bop 
{ 
    public static void main (String[] args) throws java.lang.Exception 
    { 
     // Create test data. 
     String str = "Hejsan åäö/漢ya"; 
     byte[] bytes = str.getBytes("UTF-8"); 

     String ch; 

     // Processes byte by byte, returns a valid UTF8 char when 
     //there is a complete one to get. 

     UTF8Processor processor = new UTF8Processor(); 

     for(int i=0; i<bytes.length; i++) 
     { 
      if((ch = processor.processByte(bytes[i])) != null) 
       System.out.println(ch); 
     } 
    } 
} 
+0

你应该在processByte()中调用reset() - 没有很好的理由要求外部管理缓冲区。 – Clyde

+0

@Clyde真的,不是最简单的代码,因为它在几分钟内被扔在一起。我会解决这个问题。 –

1

你有两个选择:

  • 如果你有兴趣的代码点是简单的东西(在UTF-8项)作为低于128的代码点,则可以从bytechar进行简单的转换。查找编码规则Wikipadia: UTF-8为什么这个工程的原因。

  • 如果这是不可能的,你可以看看Charset这个类,它是Java编码/解码库的根。在这里您可以找到CharsetDecoder,您可以提供N个字节并获取M个字符。一般情况是N!= M。但是,您将不得不处理ByteBufferCharBuffer

相关问题