[英]How to convert byte array to string and vice versa?
我必須在 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);
我陷入了這個問題。
您的字節數組必須有一些編碼。 如果您有負值,則編碼不能是 ASCII。 弄清楚這一點后,您可以使用以下方法將一組字節轉換為字符串:
byte[] bytes = {...}
String str = new String(bytes, StandardCharsets.UTF_8); // for UTF-8 encoding
您可以使用一堆編碼,查看Oracle javadocs中支持的編碼。
byte[]
和String
之間的“正確轉換”是明確說明您要使用的編碼。 如果您以byte[]
開頭並且它實際上不包含文本數據,則沒有“正確的轉換”。 String
用於文本, byte[]
用於二進制數據,唯一真正明智的做法是避免在它們之間進行轉換,除非絕對必要。
如果您真的必須使用String
來保存二進制數據,那么最安全的方法是使用Base64編碼。
根本問題是(我認為)您在不知不覺中使用了一個字符集:
bytes != encode(decode(bytes))
在某些情況下。 UTF-8 就是這種字符集的一個例子。 具體來說,某些字節序列不是 UTF-8 中的有效編碼。 如果 UTF-8 解碼器遇到這些序列之一,它可能會丟棄有問題的字節或將它們解碼為“無此類字符”的 Unicode 代碼點。 自然,當您嘗試將字符編碼為字節時,結果會有所不同。
解決方案是:
String.toByteArray
方法。 對於 Java,最常見的字符集在java.nio.charset.StandardCharsets
中。 如果您正在對可以包含任何 Unicode 字符值的字符串進行編碼,則建議使用 UTF-8 編碼( UTF_8
) 。
如果您想在 Java 中進行 1:1 映射,那么您可以使用ISO 拉丁字母 No. 1 - 通常稱為“Latin 1”或簡稱為“Latin”( ISO_8859_1
)。 請注意,Java 中的 Latin-1 是 Latin-1 的 IANA 版本,它將字符分配給所有可能的 256 個值,包括控制塊 C0 和 C1 。 這些是不可打印的:您不會在任何輸出中看到它們。
從 Java 8 開始,Java 包含用於 Base64 編碼/解碼的java.util.Base64
。 對於 URL 安全編碼,您可能希望使用Base64.getUrlEncoder
而不是標准編碼器。 自 Android Oreo (8),API 級別 26 以來,此類也存在於 Android 中。
我們只需要用數組構造一個新的String
: http ://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/
String s = new String(bytes);
結果字符串的字節因您使用的字符集而異。 當您調用 String# 時,new String(bytes) 和 new String(bytes, Charset.forName("utf-8")) 和 new String(bytes, Charset.forName("utf-16")) 都會有不同的字節數組# getBytes() (取決於默認字符集)
使用new String(byOriginal)
並使用getBytes()
轉換回byte[]
並不能保證兩個byte[]
具有相等的值。 這是由於調用StringCoding.encode(..)
將String
編碼為Charset.defaultCharset()
。 在此編碼期間,編碼器可能會選擇替換未知字符並進行其他更改。 因此,使用String.getBytes()
可能不會返回您最初傳遞給構造函數的相等數組。
為什么會出現問題:正如有人已經指出的那樣:如果您以 byte[] 開頭並且它實際上不包含文本數據,則沒有“正確的轉換”。 字符串用於文本,byte[] 用於二進制數據,唯一真正明智的做法是避免在它們之間進行轉換,除非絕對必要。
當我嘗試從 pdf 文件創建 byte[] 然后將其轉換為 String 然后將 String 作為輸入並轉換回文件時,我觀察到了這個問題。
因此,請確保您的編碼和解碼邏輯與我所做的相同。 我將 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();
}
雖然
new String(bytes, "UTF-8")
是正確的,它會引發UnsupportedEncodingException
,它會強制您處理已檢查的異常。 您可以使用自 Java 1.6 以來的另一個構造函數作為替代方法,將字節數組轉換為String
:
new String(bytes, StandardCharsets.UTF_8)
這個不會拋出任何異常。
轉換回來也應該使用StandardCharsets.UTF_8
完成:
"test".getBytes(StandardCharsets.UTF_8)
您再次避免處理已檢查的異常。
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;
}
這對我來說很好:
String cd = "Holding some value";
從字符串轉換為字節[]:
byte[] cookie = new sun.misc.BASE64Decoder().decodeBuffer(cd);
從 byte[] 轉換為字符串:
cd = new sun.misc.BASE64Encoder().encode(cookie);
我確實注意到了任何答案中都沒有的東西。 您可以將字節數組中的每個字節轉換為字符,並將它們放入 char 數組中。 然后字符串是
new String(cbuf)
其中 cbuf 是字符數組。
要轉換回來,循環遍歷將每個字符轉換為字節的字符串以放入一個字節數組,這個字節數組將與第一個相同。
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
應該這樣做:
byte [] b = javax.xml.bind.DatatypeConverter.parseHexBinary("E62DB");
String s = javax.xml.bind.DatatypeConverter.printHexBinary(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();
}
雖然 base64 編碼是安全的並且有人可能會爭論“正確的答案”,但我來到這里是為了尋找一種將 Java 字節數組原樣轉換為 Java 字符串/從 Java 字符串轉換為/從 Java 字符串轉換的方法。 也就是說,字節數組的每個成員在其對應的字符串中保持不變,編碼/傳輸不需要額外的空間。
這個描述 8 位透明編碼的答案對我很有幫助。 我在 TB 的二進制數據上使用ISO-8859-1
成功地來回轉換(二進制 <-> 字符串),而沒有 base64 編碼所需的膨脹空間要求,因此對我的用例 - YMMV 來說是安全的。
這也有助於解釋何時/是否應該進行實驗。
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);
以下是示例代碼安全地將字節數組轉換為字符串並將字符串轉換為字節數組。
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]
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);
}
我使用這種方法成功地將字節數組轉換為字符串:
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();
}
這個對我有用,直到 android Q:
您可以使用以下方法將 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();
}
使用以下內容將字節數組轉換為十六進制字符串
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);
}
在 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()
這里是工作代碼。
// 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);
您可以使用簡單的 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);
嘗試在兩種轉換中指定一個 8 位字符集。 例如 ISO-8859-1。
使用ByteArrayInputStream
從String
中讀取字節,並使用 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();
}
}
}
輸出是:
薩哈爾是個好孩子
InputStream is = new FileInputStream("/home/kalt/Desktop/SUDIS/READY/ds.bin");
byte[] bytes = IOUtils.toByteArray(is);
您可以執行以下操作將字節數組轉換為字符串,然后將該字符串轉換為字節數組:
// 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]
字符串是 char 的集合(16 位無符號)。 因此,如果您要將負數轉換為字符串,它們將在翻譯中丟失。
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);
}
}
使用Base64並解決您的問題。它太容易使用了。 http://iharder.sourceforge.net/current/java/base64/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.