【问题标题】:How to detect end of string in byte array to string conversion?如何检测字节数组中字符串的结尾到字符串的转换?
【发布时间】:2011-12-21 21:11:43
【问题描述】:

我从套接字接收到一个字节数组中的字符串,如下所示:

[128,5,6,3,45,0,0,0,0,0]

网络协议给出的大小是字符串的总长度(包括零)所以,在我的示例 10 中。

如果我只是这样做:

String myString = new String(myBuffer); 

我在字符串的末尾有 5 个不正确的字符。转换似乎没有检测到字符串字符 (0) 的结尾。

为了获得正确的大小和正确的字符串,我这样做:

int sizeLabelTmp = 0;
//Iterate over the 10 bit to get the real size of the string
for(int j = 0; j<(sizeLabel); j++) {
    byte charac = datasRec[j];
    if(charac == 0)
        break;
    sizeLabelTmp ++;
}
// Create a temp byte array to make a correct conversion
byte[] label    = new byte[sizeLabelTmp];
for(int j = 0; j<(sizeLabelTmp); j++) {
    label[j] = datasRec[j];
}
String myString = new String(label);

有没有更好的方法来处理这个问题?

谢谢

【问题讨论】:

    标签: java string bytearray type-conversion


    【解决方案1】:

    0 不是“字符串结尾字符”。它只是一个字节。它是否仅出现在字符串的末尾取决于您使用的编码(以及文本可以是什么)。例如,如果您使用 UTF-16,对于 ASCII 字符,每隔一个字节都会为 0。

    如果您确定第一个 0 表示字符串的结尾,您可以像您给出的代码一样使用 something,但我会重写它是:

    int size = 0;
    while (size < data.length)
    {
        if (data[size] == 0)
        {
            break;
        }
        size++;
    }
    
    // Specify the appropriate encoding as the last argument
    String myString = new String(data, 0, size, "UTF-8");
    

    强烈建议您不要只使用平台默认编码 - 它不可移植,并且可能不允许所有 Unicode 字符。但是,您不能随意决定 - 您需要确保生成和使用此数据的所有内容都在编码上达成一致。

    如果您可以控制协议,那么如果您可以在字符串之前引入一个长度前缀来指示编码形式中有多少字节,那会更好。这样您就可以准确地读取正确数量的数据(不会“过度读取”),并且可以判断数据是否由于某种原因被截断。

    【讨论】:

    • +1 用于考虑编码。如果通过套接字接收的内容只是一个序列化的 Java 字符串,那应该没问题。
    • @G_H:“只是一个序列化的 Java 字符串”并没有真正指定序列化格式是什么。如果 OP 使用 Java 二进制序列化,他无论如何都不会明确地执行此操作......如果它是其他一些序列化格式,我们需要知道 which
    • 我可能应该停止说话了...事实是,我一直远离序列化并且不太了解细节。 JAXB 或 JPA 通常是我唯一考虑的选项。
    【解决方案2】:

    Java 中的字符串不以 0 结尾,就像在其他一些语言中一样。 0 会变成所谓的空字符,允许出现在字符串中。我建议你使用一些修整方案,要么检测数组的第一个索引为 0 并使用子数组来构造字符串(假设之后所有的其余部分都为 0),或者只构造字符串并调用 @987654321 @。这将删除前导和尾随空格,即 ASCII 码为 32 或更低的任何字符。

    如果您必须保留前导空格,则后者将不起作用。在这种情况下,使用 StringBuilder 并在末尾删除字符(只要它们是空字符)会更好。

    【讨论】:

      【解决方案3】:

      您始终可以从字节数组的末尾开始并向后移动,直到遇到第一个非零值。然后只需将其复制到一个新字节中,然后将其字符串化。希望这会有所帮助:

          byte[] foo = {28,6,3,45,0,0,0,0};
          int i = foo.length - 1;
      
          while (foo[i] == 0)
          {
              i--;
          }
      
          byte[] bar = Arrays.copyOf(foo, i+1);
      
          String myString = new String(bar, "UTF-8");
          System.out.println(myString.length());
      

      会给你一个 4 的结果。

      【讨论】:

        【解决方案4】:

        在我看来,您忽略了 read() 方法返回的读取计数。尾随的空字节可能没有发送,它们可能仍然从缓冲区的初始状态遗留下来。

        int count = in.read(buffer);
        if (count < 0)
          ; // EOS: close the socket etc
        else
          String s = new String(buffer, 0, count);
        

        【讨论】:

        • 我的 OP 中显示的缓冲区只是整个数据包的提取。该字符串在许多其他数据的中间发送。
        【解决方案5】:

        可能为时已晚,但它可能会帮助其他人。您可以做的最简单的事情是new String(myBuffer).trim(),它会为您提供您想要的。

        【讨论】:

          【解决方案6】:

          不要深入研究原始 OP 提到的协议注意事项,如何修剪尾随零?

          public static String bytesToString(byte[] data) {
              String dataOut = "";
              for (int i = 0; i < data.length; i++) {
                  if (data[i] != 0x00)
                      dataOut += (char)data[i];
              }
              return dataOut;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-07-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多