2009-10-08 27 views
139

Tengo que convertir una matriz de bytes a cadena en Android, pero mi matriz de bytes contiene valores negativos.cómo convertir una matriz de bytes a una cadena y viceversa

Si vuelvo a convertir esa cadena en matriz de bytes, los valores que obtengo son diferentes de los valores originales de la matriz de bytes.

¿Qué puedo hacer para obtener la conversión adecuada? El código que estoy usando para hacer la conversión es el siguiente:

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

Estoy atascado en este problema.

+2

¿Por qué intentas convertir datos binarios arbitrarios en una cadena en primer lugar?Además de todos los problemas de juego de caracteres que las respuestas ya mencionan, también está el hecho de que estás abusando de String si haces esto. ¿Qué hay de malo en usar un 'byte []' para tus datos binarios y 'String' para tu texto? –

+5

@Joachim: a veces tiene herramientas externas que pueden hacer cosas como cadenas de tiendas. En ese caso, desea poder convertir una matriz de bytes en una cadena (codificada de alguna manera). –

Respuesta

83

La "conversión correcta" entre byte[] y es String para indicar explícitamente la codificación que desea utilizar.Si comienza con un byte[] y no contiene datos de texto, no es "conversión correcta". String s son para texto, byte[] es para datos binarios, y lo único realmente sensato es evitar convirtiendo entre ellos a menos que sea absolutamente necesario.

Si realmente debe utilizar un String para almacenar datos binarios, la forma más segura es utilizar la codificación Base64.

+1

Sí, [la codificación de caracteres es algo que debe conocer] (http://stackoverflow.com/questions/10611455/what-is-character-encoding) para convertir cadenas y bytes. – Raedwald

+3

Base64 y me salvaste la vida – mstzn

+1

La codificación Base64 resolvió mi problema. UTF-8 no funcionó para todas las entradas –

-3

Una cadena es una colección de caracteres (16 bits sin signo). Entonces, si va a convertir números negativos en una cadena, se perderán en la traducción.

+1

-1: Esto es incorrecto. Mientras que 'byte' es un tipo con signo en Java, el código de la biblioteca que trata la codificación y decodificación del juego de caracteres lo trata sin firmar. –

+0

Un buen ejemplo de por qué tener un tipo de datos de 8 bits sin signo realmente es una buena idea para tener en un idioma. Evita confusiones innecesarias; ^) – Toad

+0

Tenga cuidado al suponer que un char de Java será de 16 bits, debido a la UTF-16 de Java, pueden expandir hasta 32 bits –

0

Intente especificar un juego de caracteres de 8 bits en ambas conversiones. ISO-8859-1 por ejemplo.

218

Su matriz de bytes debe tener alguna codificación. La codificación no puede ser ASCII si tiene valores negativos. Una vez que darse cuenta de eso, se puede convertir un conjunto de bytes en una cadena mediante:

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

Hay un montón de codificaciones que puede utilizar, un vistazo a la clase de juego de caracteres en el Sun javadocs.

+4

aunque no funcionará con UTF8. –

+3

Eso fue solo una muestra, en realidad no sé qué codificación debería usar ... – omerkudat

+3

@MauricePerry ¿Puedes explicar por qué no funciona con 'UTF-8'? – UnKnown

8

El uso de new String(byOriginal) y la conversión de nuevo a byte[] utilizando getBytes() no garantiza dos byte[] con valores iguales. Esto se debe a una llamada a StringCoding.encode(..) que codificará String a Charset.defaultCharset(). Durante esta codificación, el codificador podría elegir reemplazar caracteres desconocidos y hacer otros cambios. Por lo tanto, el uso de String.getBytes() podría no devolver una matriz igual a la que originalmente le pasó al constructor.

34

La raíz del problema es (creo) que está utilizando, sin saberlo, un conjunto de caracteres para los que:

bytes != encode(decode(bytes)) 

en algunos casos. UTF-8 es un ejemplo de dicho conjunto de caracteres. Específicamente, ciertas secuencias de bytes no son codificaciones válidas en UTF-8. Si el decodificador UTF-8 encuentra una de estas secuencias, es posible que descarte los bytes ofensivos o los descodifique como el punto de código Unicode para "no dicho carácter". Naturalmente, cuando intente codificar los caracteres como bytes, el resultado será diferente.

La solución es:

  1. ser explícito acerca de la codificación de caracteres que está utilizando; es decir, use un constructor de cadenas y el método String.toByteArray con un juego de caracteres explícito.
  2. Utilice el conjunto de caracteres correcto para sus datos de bytes ... o alternativamente uno (como "Latin-1" donde todas las secuencias de bytes se correlacionan con caracteres Unicode válidos.
  3. Si sus bytes son (realmente) datos binarios y usted quiero ser capaz de transmitir/recibir ellos a través de una "basado en texto" del canal, usar algo como la codificación Base64 ... que está diseñado para este fin.
+1

¡Gracias por utilizar la codificación "Latin-1"! – Gonzo

-4

Usa Base64 y resuelve tu problema. Es demasiado fácil de usar. http://iharder.sourceforge.net/current/java/base64/

+5

Considere mejorar esta respuesta para que contenga algo más que un simple enlace. Ver http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers. –

28

sólo tenemos que construir una nueva String con la matriz: http://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/

String s = new String(bytes); 

Los bytes de la cadena resultante difiere dependiendo de qué juego de caracteres que utiliza. new String (bytes) y new String (bytes, Charset.forName ("utf-8")) y new String (bytes, Charset.forName ("utf-16")) tendrán diferentes matrices de bytes al llamar a String # getBytes() (según el juego de caracteres por defecto)

+7

No. Los bytes de la cadena resultante difieren según el conjunto de caracteres que utilice. 'new String (bytes)' y 'new String (bytes, Charset.forName (" utf-8 "))' y 'new String (bytes, Charset.forName (" utf-16 "))' tendrán bytes diferentes arrays cuando llama a 'String # getBytes()' (según el juego de caracteres predeterminado) –

+0

Engañoso. El 'char's (y por lo tanto el texto mostrado) del' String' resultante difiere al decodificar 'bytes' de manera diferente. La conversión a bytes utilizando la codificación predeterminada (use 'String # getBytes (" charset ")' para especificar lo contrario) diferirá necesariamente porque convierte entradas diferentes. Las cadenas no almacenan el 'byte []' del que están hechas, 'char's no tienen una codificación y' String' no lo almacena de otra forma. – zapl

5

¿por qué era el problema: Como alguien ya especificados: Si usted comienza con un byte [] y no lo hace, de hecho, contener datos de texto, no hay "conversión adecuada". Las cadenas son para texto, byte [] es para datos binarios, y lo único realmente sensato es evitar convertir entre ellos a menos que sea absolutamente necesario.

Estaba observando este problema cuando estaba tratando de crear byte [] desde un archivo pdf y luego convertirlo a String y luego tomar el String como entrada y convertir de nuevo a un archivo.

Así que asegúrese de que su lógica de codificación y descodificación sea la misma que yo. Codifiqué explícitamente el byte [] a Base64 y lo decodifiqué para crear el archivo nuevamente.

de casos de uso: Debido a algunas limitaciones que estaba tratando de enviado byte[] en request(POST) y el proceso fue el siguiente:

PDF File >> Base64.encodeBase64 (byte []) >> cadena >> Enviar en la solicitud (POST) >> >> recibir cadena Base64.decodeBase64 (byte []) >> crear binario

probar esto y esto funcionó para mí ..

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

Esto funciona muy bien para mí:

String cd="Holding some value"; 

La conversión de cadena a byte []:

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

Convertir de byte [] para cadena:

cd = new sun.misc.BASE64Encoder().encode(cookie); 
0
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); 
} 
+0

¿Por qué? ¿Por qué pasaría Base64 para convertir un byte a String? La sobrecarga. –

4
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; 
} 
+0

Esto no responde la pregunta. –

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


    } 

} 
+0

Pase The Charset Encoding como argumento para getBytes –

+1

Es posible que desee considerar realizar esta respuesta con una explicación además del código. –

3

javax.xml.bind.DatatypeConverter debería hacerlo:

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

I logrado convertir matriz de bytes en una cadena con este método:

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

Leer los bytes de String usando ByteArrayInputStream y lo envuelve con BufferedReader que es Char Stream en lugar de Byte Stream que convierte los datos de bytes a String.

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

    } 
} 

de salida es:

Sajal es un buen chico

4

Me di cuenta de algo que no se encuentra en ninguna de las respuestas. Puede convertir cada uno de los bytes en la matriz de bytes a caracteres y ponerlos en una matriz char. Entonces la cadena es

new String(cbuf)
donde cbuf es la matriz char. Para convertir de nuevo, recorra la cadena que convierte cada uno de los caracteres en bytes para ponerlos en una matriz de bytes, y esta matriz de bytes será la misma que la primera.


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

} 

2

He aquí algunos métodos que convierten una matriz de bytes en una cadena. Los he probado, funcionan bien.

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

} 
0

Aquí el código de trabajo.

  // 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); 
-1
InputStream is = new FileInputStream("/home/kalt/Desktop/SUDIS/READY/ds.bin"); 
byte[] bytes = IOUtils.toByteArray(is); 
0

Si bien la codificación base64 es seguro y se podría argumentar "la respuesta correcta", llegué aquí buscando una manera de convertir una matriz de bytes de Java a/desde una cadena de Java tal y como son. Es decir, donde cada miembro de la matriz de bytes permanece intacto en su contraparte de Cadena, sin que se requiera espacio adicional para la codificación/transporte.

This answer describiendo 8bit transparent encodings fue muy útil para mí. Utilicé ISO-8859-1 en terabytes de datos binarios para convertir hacia adelante y hacia atrás correctamente (< binario -> Cadena) sin los requisitos de espacio inflado necesarios para una codificación base64, por lo que es seguro para mi caso de uso - YMMV.

This was also helpful para explicar cuándo/si debe experimentar.

Cuestiones relacionadas