ByteBuffer 解码时缺少数据为字符串

Posted

技术标签:

【中文标题】ByteBuffer 解码时缺少数据为字符串【英文标题】:ByteBuffer Missing Data When decoded As string 【发布时间】:2018-12-13 11:59:26 【问题描述】:

我正在读写一个 ByteBuffer

import org.assertj.core.api.Assertions;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;

public class Solution
public static void main(String[] args) throws Exception

    final CharsetEncoder messageEncoder = Charset.forName("ISO-8859-1").newEncoder();
    String message = "TRANSACTION IGNORED";
    String carrierName= "CARR00AB";
    int messageLength = message.length()+carrierName.length()+8;


    System.out.println(" --------Fill data---------");
    ByteBuffer messageBuffer = ByteBuffer.allocate(4096);
    messageBuffer.order(ByteOrder.BIG_ENDIAN);
    messageBuffer.putInt(messageLength);
    messageBuffer.put(messageEncoder.encode(CharBuffer.wrap(carrierName)));
    messageBuffer.put(messageEncoder.encode(CharBuffer.wrap(message)));
    messageBuffer.put((byte) 0x2b);
    messageBuffer.flip();

    System.out.println("------------Extract Data Approach 1--------");

    CharsetDecoder messageDecoder = Charset.forName("ISO-8859-1").newDecoder();
    int lengthField = messageBuffer.getInt();
    System.out.println("lengthField="+lengthField);
    int responseLength = lengthField - 12;
    System.out.println("responseLength="+responseLength);
    String messageDecoded= messageDecoder.decode(messageBuffer).toString();
    System.out.println("messageDecoded="+messageDecoded);
    String decodedCarrier = messageDecoded.substring(0, carrierName.length());
    System.out.println("decodedCarrier="+ decodedCarrier);
    String decodedBody = messageDecoded.substring(carrierName.length(), messageDecoded.length() - 1);
    System.out.println("decodedBody="+decodedBody);

    Assertions.assertThat(messageLength).isEqualTo(lengthField);
    Assertions.assertThat(decodedBody).isEqualTo(message);
    Assertions.assertThat(decodedBody).isEqualTo(message);

    ByteBuffer messageBuffer2 = ByteBuffer.allocate(4096);
    messageBuffer2.order(ByteOrder.BIG_ENDIAN);
    messageBuffer2.putInt(messageLength);
    messageBuffer2.put(messageEncoder.encode(CharBuffer.wrap(carrierName)));
    messageBuffer2.put(messageEncoder.encode(CharBuffer.wrap(message)));
    messageBuffer2.put((byte) 0x2b);
    messageBuffer2.flip();

    System.out.println("---------Extract Data Approach 2--------");

    byte [] data = new byte[messageBuffer2.limit()];
    messageBuffer2.get(data);
    String dataString =new String(data, "ISO-8859-1");
    System.out.println(dataString);



它工作正常,但后来我想重构它,请参阅上面代码中的方法 2

    byte [] data = new byte[messageBuffer.limit()];
    messageBuffer.get(data);
    String dataString =new String(data, "ISO-8859-1");
    System.out.println(dataString);

 Output=     #CARR00ABTRANSACTION IGNORED+

你们能帮我解释一下吗

    为什么在解码时整数在第二种方法中丢失???

    有没有办法在第二种方法中提取整数?

【问题讨论】:

不阅读问题,您是否提供了编码? 是的,请查看我的代码 好的,我会编译我这边的代码,如果其他人还没有在我之前验证问题。 你最后的代码放在哪里了?您能提供工作示例吗? 查看更新,请在执行代码前删除断言 【参考方案1】:

好的,所以您尝试从占用4 bits 的缓冲区中读取int,然后在读取4 bits 后尝试获取整个数据

我所做的是在阅读 int 后调用 messageBuffer2.clear(); 来解决此问题。这是完整的代码

System.out.println(messageBuffer2.getInt());
byte[] data = new byte[messageBuffer2.limit()];
messageBuffer2.clear();
messageBuffer2.get(data);
String dataString = new String(data, StandardCharsets.ISO_8859_1);
System.out.println(dataString);

输出是:

35
   #CARR0033TRANSACTION IGNORED+

编辑:所以基本上当你调用clear 时,它会重置各种变量,它还会重置它所获取的位置以及它是如何修复它的。

【讨论】:

你能解释一下(背后的逻辑)调用“清除”解决这个问题吗??

以上是关于ByteBuffer 解码时缺少数据为字符串的主要内容,如果未能解决你的问题,请参考以下文章

如何将 ByteBuffer 转换为 pdf

这个 Java ByteBuffer 的行为有解释吗?

如何在 JNI 中将 char[] 转换为 ByteBuffer?

编码与解码

如何重新使用 ByteBuffer 将几个 512 字节的块写入套接字?

在 Java 中将 ByteBuffer 转换为字符串