在Java中不使用new运算符将字节数组转换为字符串

时间:2010-07-10 00:22:02

标签: java string performance bytearray

除了使用new String(bytearray)之外,有没有办法将字节数组转换为字符串?确切的问题是我通过UDP连接在网络上传输json格式的字符串。在另一端,我收到一个固定大小的字节数组(因为我不知道数组大小)并从字节数组中创建一个新的字符串。如果我这样做,我分配的整个内存都是不必要的。

为了避免这种情况,我得到字节数组将其转换为字符串,截断字符串直到最后一个有效字符,然后将其转换为字节数组并从中创建一个新字符串。如果我这样做,它只会耗尽所需的内存,但垃圾收集频率变得如此之高,因为它涉及更多的分配。做这个的最好方式是什么?

4 个答案:

答案 0 :(得分:2)

会是这样的:

String s = new String( bytearray, 0, lenOfValidData, "US-ASCII");

做你想做的事情(将字符集更改为适当的编码)?


更新

根据您的评论,您可能想尝试:

socket.receive(packet);
String strPacket = new String( packet.getData(), 0, packet.getLength(), "US-ASCII");
receiver.onReceive( strPacket);

我对Java的数据报支持不太熟悉,知道packet.getLength()是否返回截断长度或数据报的原始长度(截断前适合接收缓冲区)。创建字符串可能更安全:

String strPacket = new String( packet.getData(), 
                               0, 
                               Math.min( packet.getLength(), packet.getData().length),
                               "US-ASCII");

然后,这可能是不必要的。

答案 1 :(得分:2)

最简单和最可靠的方法是使用从UDP套接字读取的数据包的长度。 DatagramSocket.receive(...)的javadoc说:

  

从此套接字接收数据报包。当此方法返回时,DatagramPacket的缓冲区将填充接收的数据。数据报包还包含发送方的IP地址和发送方机器上的端口号。

     

此方法将一直阻塞,直到收到数据报。 数据报包对象的长度字段包含接收消息的长度。如果消息长于数据包的长度,则消息将被截断。

如果你不能这样做,那么下面将分配一个最小大小的字符串,没有不必要的临时分配。

  byte[] buff = ... // read from socket.

  // Find byte offset of first 'non-character' in buff
  int i;
  for (i = 0; i < buff.length && /* buff[i] represents a character */; i++) { /**/ }

  // Allocate String
  String res = new String(buff, 0, i, charsetName);

请注意,确定非字符的标准是字符集和特定于应用程序。但是,测试零字节就足够了。

修改

  

javadoc到底是什么意思“新字符串的长度是字符集的函数,因此可能不等于子数组的长度。” < / p>

它指出了一些字符编码(例如UTF-8,UTF-16,JIS等)的事实,一些字符由两个或多个字节表示。因此,例如,10个字节的UTF-8可能代表少于10个字符。

答案 2 :(得分:0)

您可以使用StringBuilder来避免第二次创建String。我想你的数据接收过程看起来像这样:

  1. 在客户端获取(固定大小)字节数组。
  2. 创建一个StringBuilder对象。
  3. 只要您读取有效字符并将它们附加到StringBuilder对象,就在数组上循环。
  4. 现在可以丢弃字节数组。 (我宁愿保留它,以便下次你通过网络收到一些东西,以避免不必要的内存分配。)
  5. 编辑

    我按照Tofubeer的建议使用StringBuilder代替StringBuffer

答案 3 :(得分:0)

首先可以将输入流写入ByteArrayOutputStream,然后在输出流上调用toString吗?所以像这样:

ByteArrayOutputStream os = new ByteArrayOutputStream();
while (!socket.isClosed()) {
    InputStream is = socket.getInputStream();
    byte[] buffer = new byte[1024]; // some tmp buffer.  Define the appropriate size here
    int bytesRead;
    while ((bytesRead = is.read(buffer)) != -1) {
        baos.write(buffer, 0, bytesRead);
        if (is.available() <= 0) {
            break;
        }
    }
    System.out.println(baos.toString());
    baos.reset();
}