How to convert byte[] array to String in Java
In Java, we can use new String(bytes, StandardCharsets.UTF_8) to convert a byte[] to a String .
// string to byte[] byte[] bytes = "hello".getBytes(StandardCharsets.UTF_8); // byte[] to string String s = new String(bytes, StandardCharsets.UTF_8);
1. byte[] in text and binary data
For text or character data, we use new String(bytes, StandardCharsets.UTF_8) to convert the byte[] to a String directly. However, for cases that byte[] is holding the binary data like the image or other non-text data, the best practice is to convert the byte[] into a Base64 encoded string.
// convert file to byte[] byte[] bytes = Files.readAllBytes(Paths.get("/path/image.png")); // Java 8 - Base64 class, finally. // encode, convert byte[] to base64 encoded string String s = Base64.getEncoder().encodeToString(bytes); System.out.println(s); // decode, convert base64 encoded string back to byte[] byte[] decode = Base64.getDecoder().decode(s); // This Base64 encode decode string is still widely use in // 1. email attachment // 2. embed image files inside HTML or CSS
- For text data byte[] , try new String(bytes, StandardCharsets.UTF_8) .
- For binary data byte[] , try Base64 encoding.
2. Convert byte[] to String (text data)
The below example convert a string to a byte array or byte[] and vice versa.
Warning
The common mistake is trying to use the bytes.toString() to get the string from the bytes; The bytes.toString() only returns the address of the object in memory, NOT converting byte[] to a string ! The correct way to convert byte[] to string is new String(bytes, StandardCharsets.UTF_8) .
package com.mkyong.string; import java.nio.charset.StandardCharsets; public class ConvertBytesToString2 < public static void main(String[] args) < String str = "This is raw text!"; // string to byte[] byte[] bytes = str.getBytes(StandardCharsets.UTF_8); System.out.println("Text : " + str); System.out.println("Text [Byte Format] : " + bytes); // no, don't do this, it returns the address of the object in memory System.out.println("Text [Byte Format] toString() : " + bytes.toString()); // convert byte[] to string String s = new String(bytes, StandardCharsets.UTF_8); System.out.println("Output : " + s); // old code, UnsupportedEncodingException // String s1 = new String(bytes, "UTF_8"); >>
Text : This is raw text! Text [Byte Format] : [B@372f7a8d Text [Byte Format] toString() : [B@372f7a8d Output : This is raw text!
3. Convert byte[] to String (binary data)
The below example converts an image phone.png into a byte[] , and uses the Java 8 Base64 class to convert the byte[] to a Base64 encoded String.
Later, we convert the Base64 encoded string back to the original byte[] and save it into another image named phone2.png .
package com.mkyong.string; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Base64; public class ConvertBytesToStringBase64 < public static void main(String[] args) < String filepath = "/Users/mkyong/phone.png"; Path path = Paths.get(filepath); if (Files.notExists(path)) < throw new IllegalArgumentException("File is not exists!"); >try < // convert the file's content to byte[] byte[] bytes = Files.readAllBytes(path); // encode, byte[] to Base64 encoded string String s = Base64.getEncoder().encodeToString(bytes); System.out.println(s); // decode, Base64 encoded string to byte[] byte[] decode = Base64.getDecoder().decode(s); // save into another image file. Files.write(Paths.get("/Users/mkyong/phone2.png"), decode); >catch (IOException e) < e.printStackTrace(); >> >
bh5aLyZALN4othXL2mByHo1aZA5ts5k/uw/sc7DBngGY. # if everything ok, it save the byte[] into a new image phone2.png
Converting a binary string to an ASCII string, the longer way
I had an interview recently and discovered that I’d forgotten some of the basics. I’ve been playing around again and have written a function that will take a binary string (there is no validation yet) and returns the ASCII representation of said string. I’m looking for advice or tips on how it could be improved. I don’t want to use any of the API functions, this is more of a playground scenario in which I might be able to learn something.
public static String convertBinaryStringToString(String string)< StringBuilder sb = new StringBuilder(); char[] chars = string.replaceAll("\\s", "").toCharArray(); int [] mapping = ; for (int j = 0; j < chars.length; j+=8) < int idx = 0; int sum = 0; for (int i = 7; i>= 0; i--) < if (chars[i+j] == '1') < sum += mapping[idx]; >idx++; > System.out.println(sum);//debug sb.append(Character.toChars(sum)); > return sb.toString(); >
01101000 01100101 01101100 01101100 01101111 104 101 108 108 111 hello
2 Answers 2
This seems avoidable — array access could be replaced with a bitshift. It’d also clear up what you’re doing.
for (int j = 0; j < chars.length; j+=8) < int idx = 0; int sum = 0; for (int i = 7; i>= 0; i--) < if (chars[i+j] == '1') < sum += 1 idx++; > System.out.println(sum);//debug sb.append(Character.toChars(sum)); >
It’s only after making this change that I understand what you’re doing! You’re splitting the input string into segments that represent a single character (I got that far already), but after that, you start at the back of the represented character, and check for each bit representing character that it is ‘1’. If it’s ‘1’ (and thus not ‘0’), you add the value that the bit would represent to sum. Once you’ve gone through a single character representation, you let Character.toChars cast the int-value of the character back to a character. Then you add it to the result buffer, which will form the full string.
You need more comments, so that other developers can read and understand directly how this method works.
Specifically, 1 comment to explain what your replaceAll does (regex are not obvious to me and I have to look them up), and 1 comment to say that you’re parsing bits in reverse per character.
//for each character for (int j = 0; j < chars.length; j+=8) < int idx = 0; int sum = 0; //for each bit in reverse for (int i = 7; i>= 0; i--) < if (chars[i+j] == '1') < sum += 1 idx++; > System.out.println(sum);//debug sb.append(Character.toChars(sum)); >
Getting rid of all the built-in functions (for fun only)
So you want to do everything yourself?
This is bad style, since everything in java.lang (and in generally, java.util as well) can be relied on without turning this into a puzzle for your fellow programmers, but I’ll humor you.
First, you can get rid of the String.split via Thomas Junk’s answer, incrementing by 9 each time instead.
public static String convertBinaryStringToString(String string)< StringBuilder sb = new StringBuilder(); char[] chars = string.toCharArray(); //for each character for (int j = 0; j < chars.length; j+=9) < int idx = 0; int sum = 0; //for each bit in reverse for (int i = 7; i>= 0; i--) < if (chars[i+j] == '1') < sum += 1 idx++; > System.out.println(sum);//debug sb.append(Character.toChars(sum)); > return sb.toString(); >
Leaves us with this bit of code.
We can get rid of the StringBuilder by writing to a char[] . We can get rid of Character.toChars(sum) with (char) sum . We do have to make a new string out of the character array, though.
public static String convertBinaryStringToString(String string)< char[] chars = string.toCharArray(); char[] transcoded = new char[(chars.length / 9)+1]; //for each character (plus one for spacing) for (int j = 0; j < chars.length; j+=9) < int idx = 0; int sum = 0; //for each bit in reverse for (int i = 7; i>= 0; i--) < if (chars[i+j] == '1') < sum += 1 idx++; > transcoded[j/9] = (char) sum; > return new String(transcoded); >
And voila, we’re rid of most of the built-ins. There’s no way to get the contents of a String without use of built-ins, however, so string.toCharArray or string.charAt is required.
\$\begingroup\$ thankyou! bitswise ops are something I’m not great at so this certainly helps, thank you. Have you any suggestion for how I might go about removing «Character.toChars(sum)»? \$\endgroup\$
\$\begingroup\$ @SteveGreen It’s pretty nasty, but (char) sum would do. I tried System.out.println((char)104); just now and got h . \$\endgroup\$
\$\begingroup\$ @SteveGreen updated my answer to get rid of most if not all of the built-in calls. but that’s really not recommended, it took nice code and butchered it. \$\endgroup\$
\$\begingroup\$ thanks for that, I really appreciate it. I think I’ll stop at your first suggestion of using bitwise and +=9. Butchering the code as you pointed out was never my intention but I have a much better understanding now. Thanks for solving the puzzle 😀 \$\endgroup\$
That’s okay. You could improve on your current design by these minor changes:
1) If you know, that the binaries are in blocks of 8 chars each, you could simply omit filtering the noise and incement by 9 instead of 8 characters.
2) You do not need to split the string into an array. String.charAt() does, what need.
public static String convertBinaryStringToString(String string)< StringBuilder sb = new StringBuilder(); int [] mapping = ; for (int j = 0; j < string.length(); j+=9) < int idx = 0; int sum = 0; for (int i = 7; i>= 0; i--) < if (string.charAt(i+j) == '1') < sum += mapping[idx]; >idx++; > System.out.println(sum);//debug sb.append(Character.toChars(sum)); > return sb.toString(); >
Perhaps you could go one step further: Instead of iterating over each block, you could make use of the fact, that between each block is a delimiter ( in your case). So you could get blocks by simply chopping up the string with string.split(» «) . This makes it possible to do a forEach on the resulting blocks. You could refactor the inner for-loop out.
public static String convertBinaryStringToString(String string) < StringBuilder sb = new StringBuilder(); Listblocks = Arrays.asList(string.split(" ")); for (String block:blocks) < int result=convertBlock(block); System.out.println(result); sb.append(Character.toChars(result)); >return sb.toString(); > private static int convertBlock(String block) < int [] mapping = ; int sum = 0; int blockPosition= block.length()-1; while(blockPosition>0) < if(block.charAt(blockPosition)=='1') sum+=mapping[blockPosition]; blockPosition--; >return sum; >
If you take this as a starting point, you could do it in Java8 as follows:
public static String convertBinaryStringToString(String string) < int sum=0; Listblocks = Arrays.asList(string.split(" ")); List numbers=blocks.stream().map(block -> < int[] mapping = ; return IntStream.range(0, block.length()).reduce(0, (o, n) -> < if (block.charAt(n) == '1') o += mapping[n]; return o; >); >).collect(Collectors.toList()); numbers.forEach(System.out::println); StringBuilder result= new StringBuilder(); numbers.forEach(x->< result.append(Character.toChars(x)); >); return result.toString(); >