简体   繁体   English

将字节转换为字符串的方法

[英]ways to convert bytes to STring

I am using the below code to read messages from IBM MQ using Java.我正在使用以下代码使用 Java 从 IBM MQ 读取消息。

public void asyncReadMessage() 
    {
        System.out.println("inside asyncReadmessage");
        
            
        try{
            
            com.ibm.mq.MQQueue defaultLocalQueue;
            MQQueueManager qManager=null;
            String strMessage=null;
            MQEnvironment.hostname = "reese.int.westgroup.com";
            MQEnvironment.channel = "CLIENTCONNECTION";
            MQEnvironment.port = 1414;
            String qMngrStr = "";
            qManager = new MQQueueManager(qMngrStr); 
            int openOptions = MQC.MQOO_FAIL_IF_QUIESCING |
                    MQC.MQOO_INPUT_SHARED | MQC.MQOO_BROWSE;
                    //| MQC.MQOO_INQUIRE ; 
            String queueName="COMSERV.SRCHEXT.EVENTS.PUBLISH.QA.Q01";
            System.out.println("accessing::"+queueName);
            defaultLocalQueue = qManager.accessQueue(queueName, openOptions);
            //set transport properties.
            System.out.println("set MQ props");
            MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_CLIENT);
            System.out.println("new Queuemanager");
            ArrayList<String> msglist=new ArrayList<String>();
            boolean getMore = true;
            String messageText = null;
            while(getMore)
            {  
            MQMessage getMessages = new MQMessage();
            MQGetMessageOptions gmo = new MQGetMessageOptions();
            gmo.options=MQC.MQGMO_WAIT | MQC.MQGMO_BROWSE_FIRST;
            gmo.matchOptions=MQC.MQMO_NONE;
            gmo.waitInterval=100000;
            defaultLocalQueue.get(getMessages, gmo);
            int length=getMessages.getMessageLength();
            byte[] bMsg = new byte[length];
            getMessages.readFully(bMsg);
            String retrievedmsg = new String(bMsg);
            System.out.println("retrievedmsg::"+retrievedmsg);
           
            if(!(retrievedmsg.equals("")))
            {
                MessageHandler mh = new MessageHandler();
                System.out.println("messagehandler java file:"+retrievedmsg);
                mh.processMessages(retrievedmsg);
            }
            msglist.add(retrievedmsg);
            System.out.println("msglist::"+msglist.toString());
            }
            if(defaultLocalQueue.getCurrentDepth()==0)
             {
                getMore=false;
             }
            /*for (String message : msglist)
            {
                System.out.println("message in for loop::"+message);
                MessageHandler mh = new MessageHandler();
                System.out.println("messagehandler java file:"+message);
                mh.processMessages(message);
            }*/
            }
            
            catch(Exception e)
            {
                e.printStackTrace();
            }
    }

When I print the "retrievedmsg" variable, it's getting printed as "< maestro . proces s. event".当我打印“retrievedmsg”变量时,它被打印为“< maestro . process s. event”。 Instead it should populate as "<maestro.process.event".相反,它应该填充为“<maestro.process.event”。 And also if I try to copy "< maestro . process . event" from the Catalina log file and paste it in a notepad, then only the first letter of it will be copied and other letters will not be copied.而且,如果我尝试从 Catalina 日志文件中复制“< maestro . process . event”并将其粘贴到记事本中,那么只会复制它的第一个字母,而不会复制其他字母。 Looks like it is reading as a byte.看起来它正在读取一个字节。 Correct me if I am wrong.如果我错了,请纠正我。 Please help how to achieve this.请帮助如何实现这一目标。

尝试String retrievedmsg = new String(bMsg, StandardCharsets.UTF_8)

There are many ways bytes can be interpreted as text.有很多方法可以将字节解释为文本。 Each scheme for converting between bytes and text is called a Charset .在字节和文本之间转换的每个方案都称为Charset

When you write new String(bMsg) you are converting the bytes of bMsg using the system's default Charset.当您编写new String(bMsg)您正在使用系统的默认字符集转换 bMsg 的字节。 It would appear that the bytes you received were not in that Charset.您收到的字节似乎不在该字符集中。

Whenever you try to convert between bytes and text, you need to know the Charset.每当您尝试在字节和文本之间进行转换时,您都需要了解字符集。 Using new String(byte[]) does not make the problem go away, it just means you're ignoring the issue at your peril, as you can see in this case.使用new String(byte[])不会使问题消失,它只是意味着您忽略了该问题,这将带来危险,正如您在本例中所看到的。

My guess is that your system's default charset is a one-byte Charset, like ISO-8859-1 or windows-1252, which expect one byte to represent one character, but the text you're receiving is little-endian UTF-16, which uses two bytes to represent each character.我的猜测是您系统的默认字符集是一字节字符集,如 ISO-8859-1 或 windows-1252,它们期望一个字节代表一个字符,但您收到的文本是小端 UTF-16,它使用两个字节来表示每个字符。 If that is the case, you can address it by specifying that Charset:如果是这种情况,您可以通过指定该字符集来解决它:

String retrievedmsg = new String(bMsg, StandardCharsets.UTF_16LE);

However, this alone is not a solution.但是,仅此一项并不是解决方案。 You need to find out from the provider of the message whether they will always will send messages in UTF-16LE.您需要从消息提供者那里了解他们是否会始终以 UTF-16LE 格式发送消息。 You simply cannot know how to convert bytes to text without knowing the Charset used to transmit the data.如果不知道用于传输数据的字符集,您就无法知道如何将字节转换为文本。

MQEnvironment.hostname = "reese.int.westgroup.com"; MQEnvironment.hostname = "reese.int.westgroup.com"; String queueName="COMSERV.SRCHEXT.EVENTS.PUBLISH.QA.Q01"; String queueName="COMSERV.SRCHEXT.EVENTS.PUBLISH.QA.Q01";

You should always replace private internal company values with dummy values.您应该始终用虚拟值替换私人内部公司值。

Secondly, you should be using a Hashtable and not MQEnvironment Class.其次,您应该使用 Hashtable 而不是 MQEnvironment 类。 Just read any of the Java/MQ samples that I have post here on StackOverflow.只需阅读我在 StackOverflow 上发布的任何 Java/MQ 示例。 ie MQTest11.javaMQTest11.java

"< maestro . proces s. event" “< maestro . process s. event”

That looks like Windows double byte aka character set 1252. This is not an MQ issue but rather a Java conversion issue.这看起来像 Windows 双字节又名字符集 1252。这不是 MQ 问题,而是 Java 转换问题。 What did you try?你尝试了什么? Did you try specifying the character set on the "new String" as per VGR or rsampaths16 suggested.您是否尝试按照 VGR 或 rsampaths16 建议在“新字符串”上指定字符集。

ie IE

String retrievedMsg = new String(bMsg, "cp1252");

Finally, why don't you output the message payload in a HEX dump?最后,为什么不在 HEX 转储中输出消息有效负载? That way you would know exactly what you are dealing with.这样你就可以确切地知道你在处理什么。

If you don't know how to do that then here is some sample Java code that will do it for you.如果您不知道该怎么做,那么这里有一些示例 Java 代码可以帮您完成。 Put it in your toolkit, so that you can easily add it to any project将其放入您的工具包中,以便您可以轻松地将其添加到任何项目中

/**
 * Dump a byte array as a standard HEX dump output
 * @param data the entire byte array
 * @param widthSize width of the HEX dump. Must be in multiples of 16
 */
public void dumpBuffer(byte[] data, int widthSize)
{
   int endPt = widthSize;
   int len = data.length;
   byte[] tempB = new byte[widthSize];

   if (widthSize == 16)
   {
      System.out.println("Address  0 1 2 3  4 5 6 7  8 9 A B  C D E F  0123456789ABCDEF");
      System.out.println("------- -------- -------- -------- --------  ----------------");
   }

   for (int i=0; i < len; i+=widthSize)
   {
      if (i+widthSize >= len)
         endPt = len - i;

      for (int j=0; j < endPt; j++)
         tempB[j] = data[i+j];

      System.out.println(formatHex(tempB, (i+widthSize < len?widthSize:len-i), i, widthSize ));
   }
}

/**
 * Format an array of bytes into a hex display
 * @param src a portion of the byte array
 * @param len length of this part of the byte array
 * @param index location of current position in data
 * @param width width of the HEX dump
 * @return
 */
private String formatHex(byte[] src, int lenSrc, int index, int width)
{
   String HEX = "0123456789ABCDEF";
   int i,j;
   int g = width / 4; /* number of groups of 4 bytes */
   int d = g * 9;     /* hex display width */
   StringBuffer sb = new StringBuffer();

   if ( (src == null) ||
        (lenSrc < 1) || (lenSrc > width) ||
        (index < 0) ||
        (g % 4 != 0) ||   /* only allow width of 16 / 32 / 48 etc. */
        (d < 36) )
   {
      return "";
   }

   String hdr = Integer.toHexString(index);
   if (hdr.length() <= 6)
      sb.append("000000".substring(0, 6 - hdr.length()) + hdr + ": ");
   else
      sb.append(hdr + ": ");

   /* hex display 4 by 4 */
   for(i=0; i < lenSrc; i++)
   {
      sb.append(""+HEX.charAt((src[i]) >> 4) + HEX.charAt((src[i] & 0x0F)));

      if (((i+1) % 4) == 0)
         sb.append(" ");
   }

   /* blank fill hex area if we do not have "width" bytes */
   if (lenSrc < width)
   {
      j = d - (lenSrc*2) - (lenSrc / 4);
      for(i=0; i < j; i++)
         sb.append(" ");
   }

   /* character display */
   sb.append(" ");
   for (i=0; i < lenSrc; i++)
   {
      if(Character.isISOControl((char)src[i]))
         sb.append(".");
      else
         sb.append((char)src[i]);
   }

   /* blank fill character area if we do not have "width" bytes */
   if (lenSrc < width)
   {
      j = width - lenSrc;
      for(i=0; i < j; i++)
         sb.append(" ");
   }

   return sb.toString();
}

To use this code, simply do the following:要使用此代码,只需执行以下操作:

dumpBuffer(bMsg, 16);

where bMsg is the message the code retrieved from the queue.其中 bMsg 是代码从队列中检索到的消息。 And the hex dump will look something like:十六进制转储看起来像:

Address  0 1 2 3  4 5 6 7  8 9 A B  C D E F  0123456789ABCDEF
------- -------- -------- -------- --------  ----------------
000000: 54686973 20697320 61207465 7374206D  This is a test m
000010: 65737361 67652061 6E642061 6E6F7468  essage and anoth
000020: 65722065 7863656C 6C656E74 20657861  er excellent exa
000030: 6D706C65 20627920 526F6765 722C2069  mple by Roger, i
000040: 66204920 646F2073 61792073 6F206D79  f I do say so my
000050: 73656C66 21212020 3A29               self!!  :)      

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM