我必须将字节数组转换为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);

我被这个问题难住了。


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


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


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

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

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


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


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

 bytes != encode(decode(bytes))

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

解决方案是:

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


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

如果你想在Java中实现1:1的映射,那么你可以使用ISO Latin Alphabet No. 1——通常被称为“Latin 1”或简称为“Latin”(ISO_8859_1)。注意,Java中的Latin-1是Latin-1的IANA版本,它为所有可能的256个值分配字符,包括控制块C0和C1。这些是不可打印的:您不会在任何输出中看到它们。

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


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,并将其解码以再次创建文件。

用例: 由于一些限制,我试图在请求(POST)中发送字节[],过程如下:

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

试试这个,这对我有用。

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);


    }

}

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();
}

使用ByteArrayInputStream从字符串中读取字节,并使用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位透明编码的答案对我很有帮助。我在二进制数据上使用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,迫使你处理一个checked异常。你可以使用自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]