字节数组到字符串转换的问题

时间:2018-12-11 12:14:13

标签: android arrays string hex data-conversion

我正在尝试将字节数组转换为十六进制字符串。下面是我的字节到字符串的转换方法,

public static String toHexString(byte[] bytes) {
    char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for ( int j = 0; j < bytes.length; j++ ) {
        v = bytes[j] & 0xFF;
        hexChars[j*2] = hexArray[v/16];
        hexChars[j*2 + 1] = hexArray[v%16];
    }
    return new String(hexChars);
}

问题是,发件人发送的数据是这样的

  

00 4A 60 01 02 03 04 02 10 30 38 00 00 0E 80 02 00 00 00 00 00 00 00 00 00 31 00 00 46 74 16 54 28 12 11 38 33 34 35 31 36 30 30 34 36 37 34 31 36 35 34 32 39 30 30 36 32 37 30 35 35 32 34 00 12 91 0A 59 21 8C DA FB BC D2 52 00 14

转换后我得到的是这样的

  

00 4A 60 01 02 03 04 02 10 30 38 00 00 0E EF BF BD 02 00 00 00 00 00 00 00 00 00 00 31 00 00 46 74 16 54 28 12 11 38 33 34 35 31 36 30 30 34 36 37 34 31 36 35 34 32 39 30 30 36 32 37 30 35 35 32 34 00 12 EF BF BD

虽然大多数数据相似,但是“ EFBFBD”数据以某种方式出现。

更新

评估问题所需的完整代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;

public class TCPClient {

private static final String TAG = "TCPRequest";

public static final String SERVER_IP = "X.X.X.X"; //server IP address
public static final int SERVER_PORT = xxxx;

private String mServerMessage;
// sends message received notifications
private OnMessageReceived mMessageListener = null;
// while this is true, the server will continue running
private boolean mRun = false;
// used to send messages
private OutputStream mOutStream;

private InputStream mInStream;

// used to read messages from the server
private BufferedReader mBufferIn;

byte[] bMsg = new byte[100];
int byteArr;

/**
 * Constructor of the class. OnMessagedReceived listens for the messages received from server
 */
public TCPClient(OnMessageReceived listener) {
    mMessageListener = listener;
}

/**
 * Sends the message entered by client to the server
 *
 * @param message text entered by client
 */
public void sendMessage(final String message) {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            if (mOutStream != null) {
                try {

                    byte[] bMessage = BytesUtil.hexStringToByteArray(message);
                    mOutStream.write(bMessage, 0, bMessage.length);
                    mOutStream.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    Thread thread = new Thread(runnable);
    thread.start();
}

/**
 * Close the connection and release the members
 */
public void stopClient() throws IOException {

    mRun = false;

    if (mOutStream != null) {
        mOutStream.flush();
        mOutStream.close();
    }

    mMessageListener = null;
    mServerMessage = null;

    mOutStream = null;
    mInStream = null;
}

public void run() {

    mRun = true;

    try {
        //here you must put your computer's IP address.
        InetAddress serverAddr = InetAddress.getByName(SERVER_IP);

        PrintLog.log("TCP Client", "C: Connecting...");

        //create a socket to make the connection with the server
        //Socket socket = new Socket(SERVER_IP, SERVER_PORT);
        Socket socket = new Socket();
        socket.connect(new InetSocketAddress(SERVER_IP, SERVER_PORT), 100000);

        sendMessage("requestData");

        if (socket.isConnected()) {
            PrintLog.log("CONNECTED...");
        } else {
            PrintLog.log("NOT CONNECTED: ");
        }

        try {

            //sends the message to the server
            mOutStream = socket.getOutputStream();

            //receives the message which the server sends back
            mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            //in this while the client listens for the messages sent by the server
            while (mRun) {

                bMsg = mBufferIn.readLine().getBytes();

                PrintLog.log(TAG, "Byte Array Response (Local): " + toHexString(bMsg));

                mServerMessage = new String(bMsg);

                PrintLog.log(TAG, "Listening message...");
                if (mServerMessage != null && mMessageListener != null) {
                    //call the method messageReceived from MyActivity class
                    mMessageListener.messageReceived(mServerMessage);
                }
            }

            PrintLog.log("RESPONSE FROM SERVER", "S: Received Message: '" + String.valueOf(mServerMessage) + "'");

        } catch (Exception e) {
            PrintLog.log("TCP", "S: Error" + e);
        } finally {
            //the socket must be closed. It is not possible to reconnect to this socket
            // after it is closed, which means a new socket instance has to be created.
            socket.close();
        }

    } catch (Exception e) {
        PrintLog.log("TCP", "C: Error" + e);
    }

}

public static String toHexString(byte[] bytes) {
    char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for ( int j = 0; j < bytes.length; j++ ) {
        v = bytes[j] & 0xFF;
        hexChars[j*2] = hexArray[v/16];
        hexChars[j*2 + 1] = hexArray[v%16];
    }
    return new String(hexChars);
}

//Declare the interface. The method messageReceived(String message) will must be implemented in the Activity
//class at on AsyncTask doInBackground
public interface OnMessageReceived {
    public void messageReceived(String message);
}

static String convertStreamToString(java.io.InputStream is) {
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
}

}

请帮助我解决这个问题。

谢谢。

1 个答案:

答案 0 :(得分:0)

Stringchar(2字节UTF-16)保存Unicode 文本(根据语言设计)。因此,byte[]-二进制数据-和String之间的转换始终涉及编码以及可能损坏或失败的转换。

以上可能可以通过单字节编码(如Latin-1)来纠正:

new String(hexChars, "ISO-8859-1");

但是它占用两倍的内存(char是2个字节),从本质上来说比较慢(转换字节)并且不安全。

您的版本采用默认的平台编码UTF-8,并且由于UTF-8是非常严格的格式,因此可以运行为不可转换的字节序列。

错误在于其他代码。

也许在getBytes中没有编码:

byte[] bytes = string.getBytes("ISO-8859-1");

最好只使用byte[] / ByteArrayOutputStream重写代码。


提供I / O代码后:

失败的补丁程序将是:

        mBufferIn = new BufferedReader(
                new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));

        bMsg = mBufferIn.readLine().getBytes("ISO-8859-1");

问题是,可能会读取很长的行,并且删除了行分隔符(CR,LF,NEL)。

因此,代码必须更像是模糊的:

        // receives the message which the server sends back
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        IOUtils.copy(socket.getInputStream(), baos);
        byte[] content = baos.toByteArray();