将byte[]转换为字符串,然后再转回byte[]

8
我正在处理一个代理服务器。我收到的数据是byte[],我将其转换为String以执行某些操作。现在,当我将这个新的String再转换回byte[]时,会导致未知问题。
主要就是我需要知道如何正确地将byte[]转换为String,然后再次转换回byte[]
我试图只是将byte[]转换为String,然后再次转换回byte[](以确保不是我的操作引起的问题)。
所以大概就是这样的:
// where reply is a byte[]

String str= new String(reply,0, bytesRead);
streamToClient.write(str.getBytes(), 0, bytesRead);

不等同于

streamToClient.write(reply, 0, bytesRead);

当我只发送 byte[] 而没有任何转换时,我的代理正常工作,但是当我将其从 byte[] 转换为 String,然后再转回 byte[] 时,会导致问题。

有人可以帮忙吗?=]


好像编码有点随机... 到目前为止,我只看到了"gzip, deflate",因为我正在使用一个网络代理来在 Web 浏览器和 Web 服务器之间传递数据。 - Sid
2
如果它是二进制数据,你根本不应该将其转换为“字符串”的现代定义。 - Travis Gockel
4个回答

9
byte[]转换为String,再将其转换回byte[]的最佳方法是根本不要这样做。
如果必须这样做,您必须知道生成byte[]时使用的编码方式,否则操作将使用平台默认编码方式,这可能会损坏数据,因为并非所有编码方式都能编码所有可能的字符串,也不是所有可能的字节序列在所有编码方式中都合法。这就是您的情况所发生的事情。
至于如何找出编码方式,则取决于以下几点:
- 如果您正在使用HTTP,请查看Content-Type header - 如果您的数据是XML,则应该使用XML解析器,它将为您处理编码方式 - 如果您的数据是HTML页面,则可能还有一个<meta http-equiv>
如果没有找到编码方式,则意味着您得到的是随机垃圾数据,而不是文本数据

啊哈...谢谢你详细的回答...我想我最好现在就开始着手采用一种新的代理方法。 - Sid
这是一个非常像 StackOverflow 的回答,对他的问题非常棒! :) - Mark

4
如果它是签名字节数组,那么我发现最简单的解决方案是使用BASE64EncoderStream对字节数组进行编码,这将把它转换为无符号字节。 然后,您将需要使用BASE64DecoderStream对字节进行解码,以获取原始的签名字节数组。
BASE64的POM依赖:com.sun.mail javax.mail 1.4.4
public class EncryptionUtils {

private static String ALGO = "AES";
private static  Cipher cipher;




public static String encrypt(String message, String keyString) {
    cipher = Cipher.getInstance(ALGO);
        Key key = generateKey(keyString);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return new String(BASE64EncoderStream.encode(cipher.doFinal( message.getBytes())));
}

public static String decrypt(String message, String keyString)  {

       cipher = Cipher.getInstance(ALGO);
        Key key = generateKey(keyString);
        cipher.init(Cipher.DECRYPT_MODE, key);
        return new String(cipher.doFinal(BASE64DecoderStream.decode(message.getBytes()))); 

}

private static Key generateKey(String keyString) throws NoSuchAlgorithmException {
    byte[] keyBytes = BASE64DecoderStream.decode(keyString.getBytes());
    Key key = new SecretKeySpec(keyBytes, ALGO);
    return key;
}

public static void main(String args[]) {
    byte[] keyValue = new byte[16];
    new SecureRandom().nextBytes(keyValue);
    String key = new String(BASE64EncoderStream.encode(keyValue));
    String message = "test message";
    String enc = encrypt(message, key);
    String dec = decrypt(enc, key);
    System.out.println(dec);
}}

4
您需要知道所使用的字符编码,使用该编码解码字节并重新编码为相同的字符编码。例如:
String str = new String(reply, 0, Charset.forName("UTF-8"));
bytes[] out = str.getBytes(Charset.forName("UTF-8"));
streamToClient.write(bytes, 0, bytes.length);

如果没有指定字符编码,Java会使用默认的字符编码,通常是UTF-8(甚至可能被指定为UTF-8),但HTML通常是其他编码方式。我猜这就是你的问题所在。

2
默认的字符编码通常不是UTF-8,至少在Windows上不是。 - Michael Borgwardt
大多数现代Linux发行版默认使用UTF-8编码。 - Joachim Sauer

0

我在读取套接字并发送到另一个套接字时遇到类似的问题,但我的问题是我使用了BufferedOutputStream来写输出,改为使用OutputStream后它可以工作。我认为这是缓冲输出流的问题。

String mensaje ="what I want to send";
String ip = "192.168.161.165";
int port =  2042;
tpSocket = new Socket(ip, port);
os = tpSocket.getOutputStream();
byte[] myBytes= mensaje.getBytes();
ByteArrayInputStream byarris = new ByteArrayInputStream(myBytes);
int resulta =0;
byte[] bufferOutput= new byte[1];
while((resulta = byarris.read(bufferOutput))!= -1) {
    os.write(bufferOutput);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接