除了使用new String(bytearray)
之外,有没有办法将字节数组转换为字符串?确切的问题是我通过UDP连接在网络上传输json格式的字符串。在另一端,我收到一个固定大小的字节数组(因为我不知道数组大小)并从字节数组中创建一个新的字符串。如果我这样做,我分配的整个内存都是不必要的。
为了避免这种情况,我得到字节数组将其转换为字符串,截断字符串直到最后一个有效字符,然后将其转换为字节数组并从中创建一个新字符串。如果我这样做,它只会耗尽所需的内存,但垃圾收集频率变得如此之高,因为它涉及更多的分配。做这个的最好方式是什么?
答案 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。我想你的数据接收过程看起来像这样:
我按照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();
}