1

Here is what I am trying to do. I have a byte[] that I need to store in Redis with key(say key1) Redis will store it as a String. I need to reconstruct the byte[] upon retrieving the value via the key1

 //here is a byte array byte[] bArr = new byte[] {83, 71, 86, 115, 98, 71, 56, 103, 84, 88, 73, 117, 73, 69, 104, 118, 100, 121, 66, 107, 98, 121, 66, 53, 98, 51, 85, 103, 90, 71, 56, 47}; //"Hello World"; // I will have to store this as a byte string into redis //Base64 encoding bArr = Base64.encodeBase64(bArr); String storeStr = Arrays.toString(bArr) ; // storeStr is what gets stored in redis System.out.println("storeStr>>" + storeStr+ "<<"); // I will get this string back from redis // now trying to reconstruct the byte[] byte[] aArr = Base64.decodeBase64(storeStr); System.out.println("readStr>>" + Arrays.toString(aArr)+ "<<"); 

But I get the following output:

storeStr>>[85, 48, 100, 87, 99, 50, 74, 72, 79, 71, 100, 85, 87, 69, 108, 49, 83, 85, 86, 111, 100, 109, 82, 53, 81, 109, 116, 105, 101, 85, 73, 49, 89, 106, 78, 86, 90, 49, 112, 72, 79, 67, 56, 61]<< readStr>>[-13, -98, 60, -41, 77, 60, -17, -33, 121, -45, -66, 59, -37, -65, 123, -41, 93, 52, -13, -97, 59, -21, -35, 116, -13, -113, 124, -33, -50, 124, -21, 93, 117, -41, 77, 53, -45, -33, 54, -25, 127, 53, -41, 79, 117, -41, -83, 116, -25, 93, 53, -13, -98, -9, -29, -33, 61, -41, 78, -69, -13, -50, -67, -45, -113, 117, -41, 110, -10, -17, -34, -69, -25, -82, -75]<<

What am I doing wrong? Is there any better solution to this?

0

5 Answers 5

6

Arrays.toString() doesn't transform a byte array into a String. It gives a String representation of a byte array, for debugging purposes, as List<Byte>.toString() would do.

Base64.encode() should transform a byte array into a String. And Base64.decode() should transform a base64 string into the corresponding byte array. All the Base64 libraries I've seen have such a method built-in. Yours probably has one as well. If it doesn't, Base64 containing ASCII characters, you can simply use

String storeStr = new String(base64Array, "ASCII"); 

and

byte[] bytes = storeStr.getBytes("ASCII"); 
Sign up to request clarification or add additional context in comments.

2 Comments

Found the right method:String storeStr = Base64.encodeBase64String(bArr);
Why stop at B64? Redis is binary safe, so it can handle any non-printing ASCII chars. So why use 64 possible states per character when you can use 256? Use 1/4 the space.
2

I don't know what base64 encoder you're using, but the result of using base64 to encode a byte array should already be a String... and likewise when you decode, it should convert a String to a byte[]. Unfortunately some base64 APIs aren't terribly nicely designed on that front -

I suggest you look at this public domain library which has a more sensible API:

byte[] binary = ...; String encoded = Base64.encodeBytes(binary); // Send encoded to Redis... byte[] decoded = Base64.decode(encoded); 

Comments

1

You can create a String from a byte[] using the Constructor:

//assuming you have a byte[] bytes String string = new String(bytes); 

Then write it back out with:

byte[] bytes = string.getBytes(); 

Comments

1

Remember, base 64 is called that because it has a radix of 64 (64 possible values). That means each character is 2^6, or 6 bits. Redis supports binary safe strings, so it can take even non-printing characters. There is no reason to limit ourselves to 64 pretty printing, websafe characters (why people use B64).

The other problem is ASCII is 0-127, but byte is -128 to 127, so we can't map directly, we lose half the range (2^8 vs 2^7). If we use UTF-8, we get all those bits, so 2^8 or radix 256. The result is we can stuff one byte into 1.25 B64 characters, or a single UTF-8 character. Thus, UTF-8 encoding will use ~75% of the space as the B64 encoded data. Below we get better than that because of all the extra padding = characters B64 uses.

Example, encoding 19 bytes:

B64 String: 28 characters

UTF8 String: 19 characters (32% savings!)

// setup byte[] bytes = new byte[]{-10, 1, 3, 85, 48, 100, 87, 99, 050, 74, 79, 71, 100, 85, 87, -120, 108, -128, 30}; // full UTF-8 range String outFullRange = new String(bytes, "UTF-8"); System.out.println(outFullRange); // prints �U0dWc(JOGdUW�l� // just Base64 String outB64 = Base64.encode(bytes); System.out.println(outB64);// 9gEDVTBkV2MoSk9HZFVXiGyAHg== 

Remember, since Redis is in memory, and memory is precious, you might want to switch binary data to UTF-8 encoding once you app starts to fill up for some quick space savings. The downside is that it's not as human readable as B64.

1 Comment

Thank you for your introduction of binary safe strings, but probably your new String(bytes, "UTF-8") is not correct. Not all byte sequences can be properly parsed as UTF-8 bytes without data losing. Use iso-8859-1 instead.
0

Use these 2 functions to convert and convert back

Convert.ToBase64String(en) Convert.FromBase64String(input) 

It bridge a link between byte and string. and it make sure that no data adding or losing. It is a special string.

https://en.wikipedia.org/wiki/Base64

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.