如何将字节数组转换为字符串,反之亦然?

我必须将字节数组转换为Android中的字符串,但我的字节数组包含负值。

如果我将该字符串再次转换为字节数组,我得到的值与原始字节数组值不同。

我该怎么做才能得到正确的转换?我用来做转换的代码如下:

// Code to convert byte arr to str:
byte[] by_original = {0,1,-2,3,-4,-5,6};
String str1 = new String(by_original);
System.out.println("str1 >> "+str1);


// Code to convert str to byte arr:
byte[] by_new = str1.getBytes();
for(int i=0;i<by_new.length;i++)
System.out.println("by1["+i+"] >> "+str1);

我被这个问题难住了。

738519 次浏览

字符串是char's (16bit unsigned)的集合。所以如果你要把负数转换成字符串,它们会在转换中丢失。

尝试在两个转换中都指定一个8位字符集。例如ISO-8859-1。

字节数组必须有某种编码。如果你有负值,编码就不能是ASCII。一旦你弄清楚了,你可以使用以下方法将一组字节转换为字符串:

byte[] bytes = {...}
String str = new String(bytes, StandardCharsets.UTF_8); // for UTF-8 encoding

你可以使用很多编码,看看甲骨文javadocs中支持的编码。

使用new String(byOriginal)并使用getBytes()转换回byte[]并不能保证两个值相等的byte[]。这是由于调用StringCoding.encode(..),将String编码为Charset.defaultCharset()。在这种编码过程中,编码器可能会选择替换未知字符并进行其他更改。因此,使用String.getBytes()可能不会返回最初传递给构造函数的相同数组。

根本问题是(我认为)你在不知不觉中使用了一个字符集:

 bytes != encode(decode(bytes))

在某些情况下。UTF-8就是这样一个字符集的例子。具体来说,某些字节序列在UTF-8中不是有效的编码。如果UTF-8解码器遇到这些序列中的一个,它可能会丢弃违规字节或将它们解码为“no such character&;”的Unicode码点。当然,当您尝试将字符编码为字节时,结果将有所不同。

解决方案是:

  1. 明确你所使用的字符编码;即使用String构造函数和带有显式字符集的String.toByteArray方法。
  2. 为您的字节数据使用正确的字符集…或者选择一个(如"Latin-1"其中所有字节序列都映射到有效的Unicode字符。
  3. 如果你的字节(实际上)是二进制数据,并且你希望能够通过“基于文本”的方式传输/接收它们;通道,使用类似Base64编码…哪个是为这个目的设计的

对于Java,最常见的字符集在java.nio.charset.StandardCharsets中。如果您正在编码一个可以包含任何Unicode字符值的字符串,那么建议使用UTF-8编码(UTF_8)

如果你想在Java中实现1:1的映射,那么你可以使用ISO拉丁字母第1号——更常见的叫法是“Latin 1”;或者简单的“;latin”;(ISO_8859_1)。注意,Java中的Latin-1是Latin-1的IANA版本,它为包括控制块C0和C1在内的所有可能的256个值分配字符。这些是不可打印的:您不会在任何输出中看到它们。

从Java 8开始,Java包含java.util.Base64用于Base64编码/解码。对于url安全编码,您可能希望使用Base64.getUrlEncoder而不是标准编码器。自Android Oreo(8)以来,这个类也存在于Android中,API级别为26。

byte[]String之间的“正确转换”是显式地声明你想使用的编码。如果以byte[]开始,并且它实际上不包含文本数据,则存在没有“正确转换”。__abc1用于文本,byte[]用于二进制数据,唯一真正明智的做法是在它们之间进行避免转换,除非你绝对必须这样做。

如果你真的必须使用String来保存二进制数据,那么最安全的方法是使用Base64编码。

我们只需要用数组:http://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/构造一个新的String

String s = new String(bytes);

结果字符串的字节数取决于所使用的字符集。new String(bytes)和new String(bytes, charset . forname ("utf-8"))和new String(bytes, charset . forname ("utf-16"))在调用String#getBytes()时都将有不同的字节数组(取决于默认字符集)

问题出在哪里:正如某人已经指定: 如果你从一个字节[]开始,它实际上不包含文本数据,就没有“适当的转换”。字符串是用于文本的,字节[]是用于二进制数据的,唯一真正明智的事情是避免它们之间的转换,除非你绝对必须

当我试图从pdf文件创建byte[],然后将其转换为字符串,然后将字符串作为输入并转换回文件时,我观察到了这个问题。

所以确保你的编码和解码逻辑和我做的一样。我显式地将字节[]编码为Base64,并将其解码以再次创建文件。

<强>用例: 由于一些限制,我试图在request(POST)中发送byte[],过程如下:

PDF File >> Base64.encodeBase64(byte[]) >> String >> Send in request(POST) >> receive String >> Base64.decodeBase64(byte[]) >> create binary < / >强

试试这个,这对我有用。

File file = new File("filePath");


byte[] byteArray = new byte[(int) file.length()];


try {
FileInputStream fileInputStream = new FileInputStream(file);
fileInputStream.read(byteArray);


String byteArrayStr= new String(Base64.encodeBase64(byteArray));


FileOutputStream fos = new FileOutputStream("newFilePath");
fos.write(Base64.decodeBase64(byteArrayStr.getBytes()));
fos.close();
}
catch (FileNotFoundException e) {
System.out.println("File Not Found.");
e.printStackTrace();
}
catch (IOException e1) {
System.out.println("Error Reading The File.");
e1.printStackTrace();
}

这对我来说很有效:

String cd = "Holding some value";

从字符串到字节的转换[]:

byte[] cookie = new sun.misc.BASE64Decoder().decodeBuffer(cd);

从字节[]到字符串的转换:

cd = new sun.misc.BASE64Encoder().encode(cookie);
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


private static String base64Encode(byte[] bytes)
{
return new BASE64Encoder().encode(bytes);
}


private static byte[] base64Decode(String s) throws IOException
{
return new BASE64Decoder().decodeBuffer(s);
}
private static String toHexadecimal(byte[] digest){
String hash = "";
for(byte aux : digest) {
int b = aux & 0xff;
if (Integer.toHexString(b).length() == 1) hash += "0";
hash += Integer.toHexString(b);
}
return hash;
}
public class byteString {


/**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String msg = "Hello";
byte[] buff = new byte[1024];
buff = msg.getBytes("UTF-8");
System.out.println(buff);
String m = new String(buff);
System.out.println(m);




}


}

javax.xml.bind.DatatypeConverter应该这样做:

byte [] b = javax.xml.bind.DatatypeConverter.parseHexBinary("E62DB");
String s = javax.xml.bind.DatatypeConverter.printHexBinary(b);

我成功地用这个方法将字节数组转换为字符串:

public static String byteArrayToString(byte[] data){
String response = Arrays.toString(data);


String[] byteValues = response.substring(1, response.length() - 1).split(",");
byte[] bytes = new byte[byteValues.length];


for (int i=0, len=bytes.length; i<len; i++) {
bytes[i] = Byte.parseByte(byteValues[i].trim());
}


String str = new String(bytes);
return str.toLowerCase();
}

使用ByteArrayInputStreamString读取字节,并用BufferedReader包装它,它是Char流,而不是将字节数据转换为字符串的字节流。

package com.cs.sajal;


import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;


public class TestCls {


public static void main(String[] args) {


String s=new String("Sajal is  a good boy");


try
{
ByteArrayInputStream bis;
bis=new ByteArrayInputStream(s.getBytes("UTF-8"));


BufferedReader br=new BufferedReader(new InputStreamReader(bis));
System.out.println(br.readLine());


}
catch(Exception e)
{
e.printStackTrace();
}


}
}

输出是:

萨亚尔是个好孩子

我确实注意到了一些答案里没有的东西。可以将字节数组中的每个字节强制转换为字符,并将它们放入字符数组中。然后字符串是

new String(cbuf)
,其中cbuf是char数组。要进行反向转换,需要循环将每个字符转换为字节,然后放入字节数组中,这个字节数组将与第一个字节数组相同。


public class StringByteArrTest {


public static void main(String[] args) {
// put whatever byte array here
byte[] arr = new byte[] {-12, -100, -49, 100, -63, 0, -90};
for (byte b: arr) System.out.println(b);
// put data into this char array
char[] cbuf = new char[arr.length];
for (int i = 0; i < arr.length; i++) {
cbuf[i] = (char) arr[i];
}
// this is the string
String s = new String(cbuf);
System.out.println(s);


// converting back
byte[] out = new byte[s.length()];
for (int i = 0; i < s.length(); i++) {
out[i] = (byte) s.charAt(i);
}
for (byte b: out) System.out.println(b);
}


}


下面是一些将字节数组转换为字符串的方法。我已经测试过了,效果很好。

public String getStringFromByteArray(byte[] settingsData) {


ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(settingsData);
Reader reader = new BufferedReader(new InputStreamReader(byteArrayInputStream));
StringBuilder sb = new StringBuilder();
int byteChar;


try {
while((byteChar = reader.read()) != -1) {
sb.append((char) byteChar);
}
}
catch(IOException e) {
e.printStackTrace();
}


return sb.toString();


}


public String getStringFromByteArray(byte[] settingsData) {


StringBuilder sb = new StringBuilder();
for(byte willBeChar: settingsData) {
sb.append((char) willBeChar);
}


return sb.toString();


}

这里是工作代码。

            // Encode byte array into string . TemplateBuffer1 is my bytearry variable.


String finger_buffer = Base64.encodeToString(templateBuffer1, Base64.DEFAULT);
Log.d(TAG, "Captured biometric device->" + finger_buffer);




// Decode String into Byte Array. decodedString is my bytearray[]
decodedString = Base64.decode(finger_buffer, Base64.DEFAULT);

虽然base64编码是安全的,有人可能会争论“正确的答案”,但我在这里寻找一种方法来将Java字节数组转换为Java字符串。也就是说,字节数组的每个成员在其对应的String中保持完整,不需要额外的空间用于编码/传输。

这个答案描述8位透明编码对我很有帮助。我在tb的二进制数据上使用ISO-8859-1来成功地来回转换(二进制<->字符串),而没有base64编码所需的膨胀空间要求,因此对我的用例- YMMV是安全的。

这也很有帮助解释什么时候/如果你应该实验。

你可以使用简单的for循环进行转换:

public void byteArrToString(){
byte[] b = {'a','b','$'};
String str = "";
for(int i=0; i<b.length; i++){
char c = (char) b[i];
str+=c;
}
System.out.println(str);
}

尽管

new String(bytes, "UTF-8")

如果是正确的,则抛出UnsupportedEncodingException,迫使你处理检查异常。自Java 1.6以来,你可以使用另一个构造函数作为替代,将字节数组转换为String:

new String(bytes, StandardCharsets.UTF_8)

这个函数不会抛出任何异常。

转换回也应该用StandardCharsets.UTF_8完成:

"test".getBytes(StandardCharsets.UTF_8)

同样,您可以避免处理受控异常。

这个对我来说适用于android Q:

您可以使用以下方法将十六进制字符串转换为字符串

    public static String hexToString(String hex) {
StringBuilder sb = new StringBuilder();
char[] hexData = hex.toCharArray();
for (int count = 0; count < hexData.length - 1; count += 2) {
int firstDigit = Character.digit(hexData[count], 16);
int lastDigit = Character.digit(hexData[count + 1], 16);
int decimal = firstDigit * 16 + lastDigit;
sb.append((char)decimal);
}
return sb.toString();
}

将字节数组转换为十六进制字符串

    public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
byte[] image = {...};
String imageString = Base64.encodeToString(image, Base64.NO_WRAP);

您可以执行以下操作将字节数组转换为字符串,然后将该字符串转换为字节数组:

// 1. convert byte array to string and then string to byte array


// convert byte array to string
byte[] by_original = {0, 1, -2, 3, -4, -5, 6};
String str1 = Arrays.toString(by_original);
System.out.println(str1); // output: [0, 1, -2, 3, -4, -5, 6]


// convert string to byte array
String newString = str1.substring(1, str1.length()-1);
String[] stringArray = newString.split(", ");
byte[] by_new = new byte[stringArray.length];
for(int i=0; i<stringArray.length; i++) {
by_new[i] = (byte) Integer.parseInt(stringArray[i]);
}
System.out.println(Arrays.toString(by_new)); // output: [0, 1, -2, 3, -4, -5, 6]

但是要将字符串转换为字节数组,然后将字节数组转换为字符串,可以使用下面的方法:

// 2. convert string to byte array and then byte array to string


// convert string to byte array
String str2 = "[0, 1, -2, 3, -4, -5, 6]";
byte[] byteStr2 = str2.getBytes(StandardCharsets.UTF_8);
// Now byteStr2 is [91, 48, 44, 32, 49, 44, 32, 45, 50, 44, 32, 51, 44, 32, 45, 52, 44, 32, 45, 53, 44, 32, 54, 93]


// convert byte array to string
System.out.println(new String(byteStr2, StandardCharsets.UTF_8)); // output: [0, 1, -2, 3, -4, -5, 6]
  byte[] bytes = "Techie Delight".getBytes();
// System.out.println(Arrays.toString(bytes));
 

// Create a string from the byte array without specifying
// character encoding
String string = new String(bytes);
System.out.println(string);
在Android上使用Kotlin,我发现为此目的创建一些简单的扩展函数很方便。 基于Base64编码/解码的解决方案,能够通过JSON, XML等传递:

import android.util.Base64


fun ByteArray.encodeToString() = String(Base64.encode(this, Base64.NO_WRAP), Charsets.UTF_8)


fun String.decodeToBytes(): ByteArray = Base64.decode(toByteArray(Charsets.UTF_8), Base64.NO_WRAP)

所以你可以使用它

val byteArray = byteArrayOf(0, 1, 2, -1, -2, -3)
val string = byteArray.encodeToString()
val restoredArray = string.decodeToBytes()

下面是示例代码,可以安全地将字节数组转换为字符串,并将字符串转换为字节数组。

 byte bytesArray[] = { 1, -2, 4, -5, 10};
String encoded = java.util.Base64.getEncoder().encodeToString(bytesArray);
byte[] decoded = java.util.Base64.getDecoder().decode(encoded);
System.out.println("input: "+Arrays.toString(bytesArray));
System.out.println("encoded: "+encoded);
System.out.println("decoded: "+Arrays.toString(decoded));

输出:

input: [1, -2, 4, -5, 10]
encoded: Af4E+wo=
decoded: [1, -2, 4, -5, 10]