代码之家  ›  专栏  ›  技术社区  ›  TJBlackman

给定已知大小的ArrayBuffer,获取十六进制对的字符串[重复]

  •  0
  • TJBlackman  · 技术社区  · 6 年前

    我有一个JavaScriptArrayBuffer,我想把它转换成一个十六进制字符串。

    我只能找到字符串函数的array buffer,但是我想要的是数组缓冲区的hexdump。

    0 回复  |  直到 8 年前
        1
  •  52
  •   Frxstrem    8 年前

    function buf2hex(buffer) { // buffer is an ArrayBuffer
      return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
    }
    
    // EXAMPLE:
    const buffer = new Uint8Array([ 4, 8, 12, 16 ]).buffer;
    console.log(buf2hex(buffer)); // = 04080c10

    此功能分四步工作:

    1. 为每个人 x 数组,它将该元素转换为十六进制字符串(例如。, 12 变成 c ).
    2. 然后取那个十六进制字符串,用零填充它(例如。, 变成 0c ).
    3. 最后,它接受所有十六进制值并将它们连接到一个字符串中。

    下面是另一个较长的实现,它稍微容易理解,但本质上做了相同的事情:

    function buf2hex(buffer) { // buffer is an ArrayBuffer
      // create a byte array (Uint8Array) that we can use to read the array buffer
      const byteArray = new Uint8Array(buffer);
      
      // for each element, we want to get its two-digit hexadecimal representation
      const hexParts = [];
      for(let i = 0; i < byteArray.length; i++) {
        // convert value to hexadecimal
        const hex = byteArray[i].toString(16);
        
        // pad with zeros to length 2
        const paddedHex = ('00' + hex).slice(-2);
        
        // push to array
        hexParts.push(paddedHex);
      }
      
      // join all the hex values of the elements into a single string
      return hexParts.join('');
    }
    
    // EXAMPLE:
    const buffer = new Uint8Array([ 4, 8, 12, 16 ]).buffer;
    console.log(buf2hex(buffer)); // = 04080c10
        2
  •  20
  •   NikxDa    6 年前

    这是一个甜的ES6解决方案,使用 padStart 避免了基于原型调用的可接受答案的解决方案。 它实际上也更快。

    function bufferToHex (buffer) {
        return Array
            .from (new Uint8Array (buffer))
            .map (b => b.toString (16).padStart (2, "0"))
            .join ("");
    }
    

    工作原理:

    1. 一个 Array 是从 Uint8Array 保存缓冲区数据。这是为了我们可以修改数组以保存字符串值。
    2. 所有的 阵列 项映射到它们的十六进制代码并用 0
    3. 数组被连接成一个完整的字符串。
        3
  •  7
  •   dim    6 年前

    map toString :

    function bufferToHex(buffer) {
        var s = '', h = '0123456789ABCDEF';
        (new Uint8Array(buffer)).forEach((v) => { s += h[v >> 4] + h[v & 15]; });
        return s;
    }
    

    额外的好处:您可以轻松地选择大小写输出。

    http://jsben.ch/Vjx2V

        4
  •  7
  •   Sam Claus Josh    5 年前

    下面是几种编码 ArrayBuffer 以速度为顺序。所有的方法最初都在Firefox中测试过,但后来我又在Chrome(V8)中测试过。在Chrome中,这些方法的顺序基本相同,但也有细微差别——重要的是,1是所有环境中速度最快的方法 保证金。

    如果要查看当前选定的 answer 是的,你可以继续滚动到这个列表的底部。

    注意复印贴纸

    使用溶液1 . 它既是最快的也是最好的支持。在浏览器中,唯一更快的十六进制编码方法是编写优化的C代码并编译到Web程序集。

    一。预计算十六进制/ for 循环(最快/基线)

    此方法为无符号字节的每个可能值计算2个字符的十六进制八位字节: [0, 255] ,然后只映射 阵列缓冲器 answer 用这种方法。

    const byteToHex = [];
    
    for (let n = 0; n <= 0xff; ++n)
    {
        const hexOctet = n.toString(16).padStart(2, "0");
        byteToHex.push(hexOctet);
    }
    
    function hex(arrayBuffer)
    {
        const buff = new Uint8Array(arrayBuffer);
        const hexOctets = []; // new Array(buff.length) is even faster (preallocates necessary array size), then use hexOctets[i] instead of .push()
    
        for (let i = 0; i < buff.length; ++i)
            hexOctets.push(byteToHex[buff[i]]);
    
        return hexOctets.join("");
    }
    

    2。预计算十六进制/ Array.map (大约慢30%)

    Array 原型的 map() 方法的缓冲区。这是一个更实用的方法,但是如果你真的想要速度,你将永远使用 对于 循环而不是ES6数组方法,因为所有现代JS引擎都能更好地优化它们。

    重要: 你不能使用 new Uint8Array(arrayBuffer).map(...) . 尽管 Uint8Array ArrayLike 接口,its map uint8数组 阵列 原型黑客。

    function hex(arrayBuffer)
    {
        return Array.prototype.map.call(
            new Uint8Array(arrayBuffer),
            n => byteToHex[n]
        ).join("");
    }
    

    这是一个令人失望的实验。我写这个函数是因为我认为它比Aaron预先计算的十六进制八位字节还要快——boy was I error LOL.Aaron将整个字节映射到对应的两个字符的十六进制代码,这个解决方案使用位移来获得每个字节中前4位的十六进制字符,然后是最后4位的十六进制字符,并使用 String.fromCharCode() . 老实说我想 字符串.fromCharCode()

    const asciiCodes = new Uint8Array(
        Array.prototype.map.call(
            "0123456789abcdef",
            char => char.charCodeAt()
        )
    );
    
    function hex(arrayBuffer)
    {
        const buff = new Uint8Array(buff);
        const charCodes = new Uint8Array(buff.length * 2);
    
        for (let i = 0; i < buff.length; ++i)
        {
            charCodes[i * 2] = asciiCodes[buff[i] >>> 4];
            charCodes[i * 2 + 1] = asciiCodes[buff[i] & 0xf];
        }
    
        return String.fromCharCode(...charCodes);
    }
    

    四。 Array.prototype.map() 西/ padStart()

    此方法使用 Number.toString() 方法获取十六进制,然后根据需要通过 String.padStart() 方法。

    重要: 字符串.padStart() 是一个相对较新的标准,因此如果您计划支持的浏览器超过2017年左右或Internet Explorer,则不应使用此或方法5。TBH如果你的用户仍在使用IE,你可能现在应该去他们家安装Chrome/Firefox。帮我们大家一个忙。:^D个

    function hex(arrayBuffer)
    {
        return Array.prototype.map.call(
            new Uint8Array(arrayBuffer),
            n => n.toString(16).padStart(2, "0")
        ).join("");
    }
    

    5个。 Array.from().map() 西/ (大约慢370%)

    这与#4相同,但不是 阵列 原型黑客,我们从 uint8数组 打电话来 直接说。但我们付出的代价很快。

    function hex(arrayBuffer)
    {
        return Array.from(new Uint8Array(arrayBuffer))
            .map(n => n.toString(16).padStart(2, "0"))
            .join("");
    }
    

    6。 西/ slice() (大约慢450%)

    这是选择的答案,除非您是一个典型的web开发人员,并且性能会让您感到不安,否则不要使用此答案(答案1也受许多浏览器的支持)。

    function hex(arrayBuffer)
    {
        return Array.prototype.map.call(
            new Uint8Array(arrayBuffer),
            n => ("0" + n.toString(16)).slice(-2)
        ).join("");
    }
    
        5
  •  2
  •   Aaron Watters    6 年前

    // look up tables
    var to_hex_array = [];
    var to_byte_map = {};
    for (var ord=0; ord<=0xff; ord++) {
        var s = ord.toString(16);
        if (s.length < 2) {
            s = "0" + s;
        }
        to_hex_array.push(s);
        to_byte_map[s] = ord;
    }
    
    // converter using lookups
    function bufferToHex2(buffer) {
        var hex_array = [];
        //(new Uint8Array(buffer)).forEach((v) => { hex_array.push(to_hex_array[v]) });
        for (var i=0; i<buffer.length; i++) {
            hex_array.push(to_hex_array[buffer[i]]);
        }
        return hex_array.join('')
    }
    // reverse conversion using lookups
    function hexToBuffer(s) {
        var length2 = s.length;
        if ((length2 % 2) != 0) {
            throw "hex string must have length a multiple of 2";
        }
        var length = length2 / 2;
        var result = new Uint8Array(length);
        for (var i=0; i<length; i++) {
            var i2 = i * 2;
            var b = s.substring(i2, i2 + 2);
            result[i] = to_byte_map[b];
        }
        return result;
    }
    

    此解决方案比上一个基准测试的获胜者更快: http://jsben.ch/owCk5 在Mac笔记本电脑上测试了Chrome和Firefox。另请参见测试验证函数的基准代码。

    [编辑:我将forEach更改为for循环,现在速度更快。]

        6
  •  1
  •   Flavien Volken    6 年前

    ArrayBuffer 与节点转储的方式相同 Buffer s。

    function pad(n: string, width: number, z = '0') {
        return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
    }
    function hexdump(buf: ArrayBuffer) {
        let view = new Uint8Array(buf);
        let hex = Array.from(view).map(v => this.pad(v.toString(16), 2));
        return `<Buffer ${hex.join(" ")}>`;
    }
    

    Example

    const buffer = new Uint8Array([ 4, 8, 12, 16 ]).buffer;
    console.log(hexdump(buffer)); // <Buffer 04 08 0c 10>
    
        7
  •  1
  •   shtse8    5 年前

    将arraybuffer转换为十六进制的最简单方法是:

    const buffer = new Uint8Array([ 4, 8, 12, 16 ]);
    console.log(Buffer.from(buffer).toString("hex")); // = 04080c10