相关文章推荐
卖萌的麦片  ·  153-Illegal mix of ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I have a byte array of the form [4,-101,122,-41,-30,23,-28,3,..] which I want to convert in the form 6d69f597b217fa333246c2c8 I'm using below function

function toHexString(bytes) {
  return bytes.map(function(byte) {
    return (byte & 0xFF).toString(16)
  }).join('')

which is giving me a string of the same form but I suspect that it's not an efficient conversion because the hex string is bit shorter than expected. I think translating should get "0a10a6dc". Please tell me if I'm wrong or is this a right conversion but maybe I'm not using the right byte array

byte array 4,-127,45,126,58,-104,41,-27,-43,27,-35,100,-50,-77,93,-16,96,105,-101,-63,48,-105,49,-67,110,111,26,84,67,-89,-7,-50,10,-12,56,47,-49,-42,-11,-8,-96,-117,-78,97,-105,9,-62,-44,-97,-73,113,96,23,112,-14,-62,103,-104,90,-14,117,78,31,-116,-7

Corresponding conversion 4812d7e3a9829e5d51bdd64ceb35df060699bc1309731bd6e6f1a5443a7f9ceaf4382fcfd6f5f8a08bb261979c2d49fb771601770f2c267985af2754e1f8cf9

Sorry, I have updated the code. I changed the variables before posting but now I'm using the original code – Actung Dec 16, 2015 at 10:56

You are missing the padding in the hex conversion. You'll want to use

function toHexString(byteArray) {
  return Array.from(byteArray, function(byte) {
    return ('0' + (byte & 0xFF).toString(16)).slice(-2);
  }).join('')

so that each byte transforms to exactly two hex digits. Your expected output would be 04812d7e3a9829e5d51bdd64ceb35df060699bc1309731bd6e6f1a5443a7f9ce0af4382fcfd6f5f8a08bb2619709c2d49fb771601770f2c267985af2754e1f8cf9

@DavidCallanan grantpatternson was commenting on an old version of the answer, where I had used byteArray.map instead of Array.from – Bergi Jul 1, 2021 at 13:01 Same thing, but in a more compact form: const toHexString = byteArray => Array.from(byteArray, byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('') – oittaa Mar 16, 2022 at 0:28 @Lance It casts the byte to an integer between 0 and 255. This is not necessary if the array elements already are unsigned octets ("bytes"), but e.g. the OP has signed integers. – Bergi Apr 16, 2022 at 20:07

Using map() won't work if the input is of a type like Uint8Array: the result of map() is also Uint8Array which can't hold the results of string conversion.

function toHexString(byteArray) {
  var s = '0x';
  byteArray.forEach(function(byte) {
    s += ('0' + (byte & 0xFF).toString(16)).slice(-2);
  return s;
                Warning: It's getting "FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory".
– Silvio Guedes
                Apr 22, 2021 at 23:33

A more concise and performant (see https://jsperf.com/byte-array-to-hex-string) alternative using Array.reduce():

function toHexString(byteArray) {
  return byteArray.reduce((output, elem) => 
    (output + ('0' + elem.toString(16)).slice(-2)),

(Also without "& 0xFF" because in my opinion if an array is passed in that contains values larger than 255, the output should be messed up, so that the user can more easily see that their input was wrong.)

Note that the & 0xFF might be necessary if the byteArray contains signed bytes that go from -128 to 127 instead of 0 to 255. – looper Oct 24, 2019 at 9:26 I'm surprised this is more performant, because it looks like its runtime is quadratic in the length of the byte array. Did you only try it on small arrays (the jsperf link is dead, BTW)? Or is javascript really smart about re-using the output location on each iteration of the reduce? – Alex Coventry Jul 28, 2020 at 1:14

Since this is the first Google hit for "js byte to hex" and I needed some time to understand the function of Bergi, I rewrote the function and added some comments that made it easier for me to understand:

function byteToHex(byte) {
  // convert the possibly signed byte (-128 to 127) to an unsigned byte (0 to 255).
  // if you know, that you only deal with unsigned bytes (Uint8Array), you can omit this line
  const unsignedByte = byte & 0xff;
  // If the number can be represented with only 4 bits (0-15), 
  // the hexadecimal representation of this number is only one char (0-9, a-f). 
  if (unsignedByte < 16) {
    return '0' + unsignedByte.toString(16);
  } else {
    return unsignedByte.toString(16);
// bytes is an typed array (Int8Array or Uint8Array)
function toHexString(bytes) {
  // Since the .map() method is not available for typed arrays, 
  // we will convert the typed array to an array using Array.from().
  return Array.from(bytes)
    .map(byte => byteToHex(byte))
    .join('');
  • For more information about the const unsignedByte = byte & 0xff-part, check What does AND 0xFF do?.
  • Array.from is not available in every browser (e.g. not in IE11), check How to convert a JavaScript Typed Array into a JavaScript Array for more information
  • The OP forgot to add the leading 0 for numbers that can be displayed with only 4 bits.

    All of the previous solutions work but they all require the creation of many strings and concatenation and slicing of the created strings. I got thinking there has to be a better way to go about it now that there are typed arrays. I originally did this using node and then commented out the lines that use Buffer and changed them to TypedArrays so it would work in a browser too.

    It's more code but it's significantly faster, at least in the quick jsperf (no longer working) I put together. The string manipulation version in the accepted answer performed 37000 ops/sec while the code below managed 317000 ops/sec. There is a lot of hidden overhead in creating string objects.

    function toHexString (byteArray) {
      //const chars = new Buffer(byteArray.length * 2);
      const chars = new Uint8Array(byteArray.length * 2);
      const alpha = 'a'.charCodeAt(0) - 10;
      const digit = '0'.charCodeAt(0);
      let p = 0;
      for (let i = 0; i < byteArray.length; i++) {
          let nibble = byteArray[i] >>> 4;
          chars[p++] = nibble > 9 ? nibble + alpha : nibble + digit;
          nibble = byteArray[i] & 0xF;
          chars[p++] = nibble > 9 ? nibble + alpha : nibble + digit;    
      //return chars.toString('utf8');
      return String.fromCharCode.apply(null, chars);
                    if the input array is signed then this line let nibble = byteArray[i] >>> 4 needs to be changed to let nibble = byteArray[i] >>> 4 & 0xF;
    – bmacnaughton
                    Apr 16, 2021 at 11:47
    

    IMHO, A simpler solution with Typescript:

    const convertHashToHex = (value: TypedArray | number[]) : string => {
      return value.map(v => v.toString(16).padStart(2, '0')).join('');
    

    JS version:

    const convertHashToHex = (value) => {
      return value.map(v => v.toString(16).padStart(2, '0')).join('');
                    That is not related with the original question, but if you open it, I would be happy to respond
    – Roberto
                    Aug 29, 2022 at 12:40
    

    When converting a byte array to a hex array, we have to consider how they can be signed numbers. If so, we gotta convert them to decimal numbers first. signed numbers to decimal conversion. Then, we can use the .toString(16) method to convert it to hex.

    const hexArr = byteArr.map((byte) => {
        if (byte < 0) {
          byte = -((byte ^ 0xff) + 1); //converting 2s complement to a decimal number
        //add padding at the start to ensure it's always 2 characters long otherwise '01' will be '1'
        return byte.toString(16).padStart(2, '0'); 
    

    This is cross-browser solution for ArrayBuffer:

        function buf2hex(buffer) {
            var u = new Uint8Array(buffer),
                a = new Array(u.length),
                i = u.length;
            while (i--) // map to hex
                a[i] = (u[i] < 16 ? '0' : '') + u[i].toString(16);
            u = null; // free memory
            return a.join('');
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.