3

I have the following code which is used to encode byte array to HEX string

private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
public static void WriteHexBytes(byte[] data, StringBuilder sb)
{
    char[] chars = new char[data.length*2];
    for (int i = 0; i < data.length; ++i)
    {
        chars[2*i] = HEX_CHARS[(data[i] & 0xF0) >>> 4];
        chars[2*i + 1] = HEX_CHARS[data[i] & 0x0F];
    }
    sb.append(chars);
}

The for loop is very slow, it takes about 10 seconds to encode 3MB of bytes on real device. On the emulator it takes like forever. The sb.append is performed instantly.

Is this normal? It seems very slow to me? What is causing slowness?

Tested on Samsung Galaxy Tab 2 7.0

Dusan
  • 5,000
  • 6
  • 41
  • 58

3 Answers3

1

It's not obvious that there is a faster approach than what you show, from a Java perspective. Apache Common's code looks slightly better than yours, but that's really just a vague guess.

From here on, if you need more, you'll just have to Microbenchmark on your hardware, I'm afraid :(.

Just out of idleness … I did micro benchmark (ad-hoc, unscientific) your solution and one I just cooked up -- you win by a factor of two. Here's what I tried:

public static void niko(byte[] data, StringBuilder sb)
{
    for (byte element : data) {
        sb.append(toChar((element & 0xf0) >>> 4));
        sb.append(toChar(element & 0x0f));
    }
}

static char toChar(int b) {
    int offset = b < 10 ? 48 : 87;
    return (char) (b + offset);
}

Going thru 10 MB 100 times, your code completes in 4 seconds, mine in 8. But keep in mind that this is very hardware dependent, JVM-dependenect, etc.

nes1983
  • 15,209
  • 4
  • 44
  • 64
  • Wow! Which hardware or device? Your results are more than 100x better than mine! On my Galaxy Tab 2 7.0, Android 4.1 for 3MB just 1 time takes between 5 and 10 seconds??? I would expect that code is slower on mobile device, but hundreds of times slower??? What is wrong? Just the simple for loop from 1..3M takes 2 seconds to complete... This speed is like on 40MHz Intel 386 or even worse. – Dusan Apr 27 '13 at 16:29
0

I'd prefer to write this as a comment (can't try whether this makes a difference on Android), but I can't write formatted code in comments... :-/

You could try caching some values to avoid some invokations:

int len = data.length;
char[] chars = new char[len * 2];
for (int i = 0; i < len; ++i) {
    int b = data[i] & 0xff;
    chars[2*i] = HEX_CHARS[b >>> 4];
    chars[2*i + 1] = HEX_CHARS[b & 0x0F];
}

p.s.

If returning a String instead of writing to StringBuilder is fine, you could also try to write to a byte array instead of a char array to reduce the allocated memory size, then construct the string from the byte array.

Stefan Haustein
  • 18,427
  • 3
  • 36
  • 51
0

Here is another suggestion:

public static void writeHexBytes(byte[] data, StringBuilder sb) {
    for (byte b : data) {
        sb.append(String.format("%02X", b));
    }
}
matsev
  • 32,104
  • 16
  • 121
  • 156