简体   繁体   English

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

[英]How to convert byte array to string and vice versa?

I have to convert a byte array to string in Android, but my byte array contains negative values.我必须在 Android 中将字节数组转换为字符串,但我的字节数组包含负值。

If I convert that string again to byte array, values I am getting are different from original byte array values.如果我再次将该字符串转换为字节数组,我得到的值与原始字节数组值不同。

What can I do to get proper conversion?我该怎么做才能获得正确的转换? Code I am using to do the conversion is as follows:我用来进行转换的代码如下:

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

I am stuck in this problem.我陷入了这个问题。

Your byte array must have some encoding.您的字节数组必须有一些编码。 The encoding cannot be ASCII if you've got negative values.如果您有负值,则编码不能是 ASCII。 Once you figure that out, you can convert a set of bytes to a String using:弄清楚这一点后,您可以使用以下方法将一组字节转换为字符串:

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

There are a bunch of encodings you can use, look at the supported encodings in the Oracle javadocs .您可以使用一堆编码,查看Oracle javadocs中支持的编码。

The "proper conversion" between byte[] and String is to explicitly state the encoding you want to use. byte[]String之间的“正确转换”是明确说明您要使用的编码。 If you start with a byte[] and it does not in fact contain text data, there is no "proper conversion".如果您以byte[]开头并且它实际上不包含文本数据,则没有“正确的转换”。 String s are for text, byte[] is for binary data, and the only really sensible thing to do is to avoid converting between them unless you absolutely have to. String用于文本, byte[]用于二进制数据,唯一真正明智的做法是避免在它们之间进行转换,除非绝对必要。

If you really must use a String to hold binary data then the safest way is to use Base64 encoding.如果您真的必须使用String来保存二进制数据,那么最安全的方法是使用Base64编码。

The root problem is (I think) that you are unwittingly using a character set for which:根本问题是(我认为)您在不知不觉中使用了一个字符集:

 bytes != encode(decode(bytes))

in some cases.在某些情况下。 UTF-8 is an example of such a character set. UTF-8 就是这种字符集的一个例子。 Specifically, certain sequences of bytes are not valid encodings in UTF-8.具体来说,某些字节序列不是 UTF-8 中的有效编码。 If the UTF-8 decoder encounters one of these sequences, it is liable to discard the offending bytes or decode them as the Unicode codepoint for "no such character".如果 UTF-8 解码器遇到这些序列之一,它可能会丢弃有问题的字节或将它们解码为“无此类字符”的 Unicode 代码点。 Naturally, when you then try to encode the characters as bytes the result will be different.自然,当您尝试将字符编码为字节时,结果会有所不同。

The solution is:解决方案是:

  1. Be explicit about the character encoding you are using;明确说明您使用的字符编码; ie use a String constructor and String.toByteArray method with an explicit charset.即使用带有显式字符集的String 构造函数和String.toByteArray方法。
  2. Use the right character set for your byte data ... or alternatively one (such as "Latin-1" where all byte sequences map to valid Unicode characters.为您的字节数据使用正确的字符集……或者使用一个字符集(例如“Latin-1”,其中所有字节序列都映射到有效的 Unicode 字符。
  3. If your bytes are (really) binary data and you want to be able to transmit / receive them over a "text based" channel, use something like Base64 encoding ... which is designed for this purpose .如果您的字节是(真正的)二进制数据,并且您希望能够通过“基于文本的”通道传输/接收它们,请使用类似 Base64 编码的东西......这是为此目的而设计的

For Java, the most common character sets are in java.nio.charset.StandardCharsets .对于 Java,最常见的字符集在java.nio.charset.StandardCharsets中。 If you are encoding a string that can contain any Unicode character value then UTF-8 encoding ( UTF_8 ) is recommended.如果您正在对可以包含任何 Unicode 字符值的字符串进行编码,则建议使用 UTF-8 编码( UTF_8 )

If you want a 1:1 mapping in Java then you can use ISO Latin Alphabet No. 1 - more commonly just called "Latin 1" or simply "Latin" ( ISO_8859_1 ).如果您想在 Java 中进行 1:1 映射,那么您可以使用ISO 拉丁字母 No. 1 - 通常称为“Latin 1”或简称为“Latin”( ISO_8859_1 )。 Note that Latin-1 in Java is the IANA version of Latin-1 which assigns characters to all possible 256 values including control blocks C0 and C1 .请注意,Java 中的 Latin-1 是 Latin-1 的 IANA 版本,它将字符分配给所有可能的 256 个值,包括控制块 C0 和 C1 These are not printable: you won't see them in any output.这些是不可打印的:您不会在任何输出中看到它们。

From Java 8 onwards Java contains java.util.Base64 for Base64 encoding / decoding.从 Java 8 开始,Java 包含用于 Base64 编码/解码的java.util.Base64 For URL-safe encoding you may want to to use Base64.getUrlEncoder instead of the standard encoder .对于 URL 安全编码,您可能希望使用Base64.getUrlEncoder而不是标准编码器 This class is also present in Android since Android Oreo (8), API level 26.自 Android Oreo (8),API 级别 26 以来,此类也存在于 Android 中。

We just need to construct a new String with the array: http://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/我们只需要用数组构造一个新的Stringhttp ://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/

String s = new String(bytes);

The bytes of the resulting string differs depending on what charset you use.结果字符串的字节因您使用的字符集而异。 new String(bytes) and new String(bytes, Charset.forName("utf-8")) and new String(bytes, Charset.forName("utf-16")) will all have different byte arrays when you call String#getBytes() (depending on the default charset)当您调用 String# 时,new String(bytes) 和 new String(bytes, Charset.forName("utf-8")) 和 new String(bytes, Charset.forName("utf-16")) 都会有不同的字节数组# getBytes() (取决于默认字符集)

Using new String(byOriginal) and converting back to byte[] using getBytes() doesn't guarantee two byte[] with equal values.使用new String(byOriginal)并使用getBytes()转换回byte[]并不能保证两个byte[]具有相等的值。 This is due to a call to StringCoding.encode(..) which will encode the String to Charset.defaultCharset() .这是由于调用StringCoding.encode(..)String编码为Charset.defaultCharset() During this encoding, the encoder might choose to replace unknown characters and do other changes.在此编码期间,编码器可能会选择替换未知字符并进行其他更改。 Hence, using String.getBytes() might not return an equal array as you've originally passed to the constructor.因此,使用String.getBytes()可能不会返回您最初传递给构造函数的相等数组。

Why was the problem: As someone already specified: If you start with a byte[] and it does not in fact contain text data, there is no "proper conversion".为什么会出现问题:正如有人已经指出的那样:如果您以 byte[] 开头并且它实际上不包含文本数据,则没有“正确的转换”。 Strings are for text, byte[] is for binary data, and the only really sensible thing to do is to avoid converting between them unless you absolutely have to.字符串用于文本,byte[] 用于二进制数据,唯一真正明智的做法是避免在它们之间进行转换,除非绝对必要。

I was observing this problem when I was trying to create byte[] from a pdf file and then converting it to String and then taking the String as input and converting back to file.当我尝试从 pdf 文件创建 byte[] 然后将其转换为 String 然后将 String 作为输入并转换回文件时,我观察到了这个问题。

So make sure your encoding and decoding logic is same as I did.因此,请确保您的编码和解码逻辑与我所做的相同。 I explicitly encoded the byte[] to Base64 and decoded it to create the file again.我将 byte[] 显式编码为 Base64 并对其进行解码以再次创建文件。

Use-case: Due to some limitation I was trying to sent byte[] in request(POST) and the process was as follows:用例:由于某些限制,我试图在request(POST)中发送byte[] ,过程如下:

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

Try this and this worked for me..试试这个,这对我有用..

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

Even though虽然

new String(bytes, "UTF-8")

is correct it throws a UnsupportedEncodingException which forces you to deal with a checked exception.是正确的,它会引发UnsupportedEncodingException ,它会强制您处理已检查的异常。 You can use as an alternative another constructor since Java 1.6 to convert a byte array into a String :您可以使用自 Java 1.6 以来的另一个构造函数作为替代方法,将字节数组转换为String

new String(bytes, StandardCharsets.UTF_8)

This one does not throw any exception.这个不会抛出任何异常。

Converting back should be also done with StandardCharsets.UTF_8 :转换回来也应该使用StandardCharsets.UTF_8完成:

"test".getBytes(StandardCharsets.UTF_8)

Again you avoid having to deal with checked exceptions.您再次避免处理已检查的异常。

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

This works fine for me:这对我来说很好:

String cd = "Holding some value";

Converting from string to byte[]:从字符串转换为字节[]:

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

Converting from byte[] to string:从 byte[] 转换为字符串:

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

I did notice something that is not in any of the answers.我确实注意到了任何答案中都没有的东西。 You can cast each of the bytes in the byte array to characters, and put them in a char array.您可以将字节数组中的每个字节转换为字符,并将它们放入 char 数组中。 Then the string is然后字符串是

new String(cbuf)
where cbuf is the char array. 其中 cbuf 是字符数组。 To convert back, loop through the string casting each of the chars to bytes to put into a byte array, and this byte array will be the same as the first. 要转换回来,循环遍历将每个字符转换为字节的字符串以放入一个字节数组,这个字节数组将与第一个相同。

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

javax.xml.bind.DatatypeConverter should do it: javax.xml.bind.DatatypeConverter应该这样做:

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

Heres a few methods that convert an array of bytes to a string.下面是一些将字节数组转换为字符串的方法。 I've tested them they work well.我已经对它们进行了测试,它们运行良好。

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

}

While base64 encoding is safe and one could argue "the right answer", I arrived here looking for a way to convert a Java byte array to/from a Java String as-is.虽然 base64 编码是安全的并且有人可能会争论“正确的答案”,但我来到这里是为了寻找一种将 Java 字节数组原样转换为 Java 字符串/从 Java 字符串转换为/从 Java 字符串转换的方法。 That is, where each member of the byte array remains intact in its String counterpart, with no extra space required for encoding/transport.也就是说,字节数组的每个成员在其对应的字符串中保持不变,编码/传输不需要额外的空间。

This answer describing 8bit transparent encodings was very helpful for me.这个描述 8 位透明编码的答案对我很有帮助。 I used ISO-8859-1 on terabytes of binary data to convert back and forth successfully (binary <-> String) without the inflated space requirements needed for a base64 encoding, so is safe for my use-case - YMMV.我在 TB 的二进制数据上使用ISO-8859-1成功地来回转换(二进制 <-> 字符串),而没有 base64 编码所需的膨胀空间要求,因此对我的用例 - YMMV 来说是安全的。

This was also helpful in explaining when/if you should experiment. 这也有助于解释何时/是否应该进行实验。

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

Following is the sample code safely converts byte array to String and String to byte array back.以下是示例代码安全地将字节数组转换为字符串并将字符串转换为字节数组。

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

Output:输出:

input: [1, -2, 4, -5, 10]
encoded: Af4E+wo=
decoded: [1, -2, 4, -5, 10]
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);
}

I succeeded converting byte array to a string with this method:我使用这种方法成功地将字节数组转换为字符串:

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

This one works for me up to android Q:这个对我有用,直到 android Q:

You can use the following method to convert o hex string to string您可以使用以下方法将 o 十六进制字符串转换为字符串

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

with the following to convert a byte array to a hex string使用以下内容将字节数组转换为十六进制字符串

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

Using Kotlin on Android I found out it is handy to create some simple extension functions for that purpose.在 Android 上使用 Kotlin 我发现为此目的创建一些简单的扩展函数很方便。 Solution based on Base64 encoding/decoding to be able to pass via JSON, XML, etc:基于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)

So you can use it所以你可以使用它

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

Here the working code.这里是工作代码。

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

You can use simple for loop for conversion:您可以使用简单的 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);
}
byte[] image = {...};
String imageString = Base64.encodeToString(image, Base64.NO_WRAP);

Try to specify an 8-bit charset in both conversions.尝试在两种转换中指定一个 8 位字符集。 ISO-8859-1 for instance.例如 ISO-8859-1。

Read the bytes from String using ByteArrayInputStream and wrap it with BufferedReader which is Char Stream instead of Byte Stream which converts the byte data to String.使用ByteArrayInputStreamString中读取字节,并使用 BufferedReader 进行包装, BufferedReader是 Char Stream 而不是将字节数据转换为 String 的 Byte Stream。

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

    }
}

Output is:输出是:

Sajal is a good boy萨哈尔是个好孩子

InputStream is = new FileInputStream("/home/kalt/Desktop/SUDIS/READY/ds.bin");
byte[] bytes = IOUtils.toByteArray(is);

You can do the following to convert byte array to string and then convert that string to byte array:您可以执行以下操作将字节数组转换为字符串,然后将该字符串转换为字节数组:

// 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]

But to convert the string to byte array and then convert that byte array to string, below approach can be used:但是要将字符串转换为字节数组,然后将该字节数组转换为字符串,可以使用以下方法:

// 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]

A string is a collection of char's (16bit unsigned).字符串是 char 的集合(16 位无符号)。 So if you are going to convert negative numbers into a string, they'll be lost in translation.因此,如果您要将负数转换为字符串,它们将在翻译中丢失。

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


    }

}

Use Base64 and solve your problem.Its too much easy to use. 使用Base64并解决您的问题。它太容易使用了。 http://iharder.sourceforge.net/current/java/base64/ http://iharder.sourceforge.net/current/java/base64/

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

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