我有一些UTF-8编码的数据生活在Javascript Uint8Array元素的范围内。是否有一种有效的方法来解码这些到一个常规的javascript字符串(我相信javascript使用16位Unicode)?我不想一次添加一个字符,因为字符串连接会变得CPU密集。


当前回答

来自Encoding标准的TextEncoder和TextDecoder,由stringencoding库填充,在字符串和ArrayBuffers之间转换:

var uint8array = new TextEncoder().encode("someString");
var string = new TextDecoder().decode(uint8array);

其他回答

来自Encoding标准的TextEncoder和TextDecoder,由stringencoding库填充,在字符串和ArrayBuffers之间转换:

var uint8array = new TextEncoder().encode("someString");
var string = new TextDecoder().decode(uint8array);

对于ES6和UTF8字符串

decodeURIComponent(escape(String.fromCharCode(...uint8arrData)))

Albert给出的解决方案,只要不经常调用所提供的函数,并且只用于大小适中的数组,就能很好地工作,否则效率非常低。下面是一个增强的普通JavaScript解决方案,它适用于Node和浏览器,具有以下优点:

•有效工作于所有八字节数组大小

•不生成中间丢弃字符串

•在现代JS引擎上支持4字节字符(否则“?”将被替换)

var utf8ArrayToStr = (function () {
    var charCache = new Array(128);  // Preallocate the cache for the common single byte chars
    var charFromCodePt = String.fromCodePoint || String.fromCharCode;
    var result = [];

    return function (array) {
        var codePt, byte1;
        var buffLen = array.length;

        result.length = 0;

        for (var i = 0; i < buffLen;) {
            byte1 = array[i++];

            if (byte1 <= 0x7F) {
                codePt = byte1;
            } else if (byte1 <= 0xDF) {
                codePt = ((byte1 & 0x1F) << 6) | (array[i++] & 0x3F);
            } else if (byte1 <= 0xEF) {
                codePt = ((byte1 & 0x0F) << 12) | ((array[i++] & 0x3F) << 6) | (array[i++] & 0x3F);
            } else if (String.fromCodePoint) {
                codePt = ((byte1 & 0x07) << 18) | ((array[i++] & 0x3F) << 12) | ((array[i++] & 0x3F) << 6) | (array[i++] & 0x3F);
            } else {
                codePt = 63;    // Cannot convert four byte code points, so use "?" instead
                i += 3;
            }

            result.push(charCache[codePt] || (charCache[codePt] = charFromCodePt(codePt)));
        }

        return result.join('');
    };
})();

在一个Chrome示例应用程序中可以找到,尽管这意味着对于更大的数据块,您可以接受异步转换。

/**
 * Converts an array buffer to a string
 *
 * @private
 * @param {ArrayBuffer} buf The buffer to convert
 * @param {Function} callback The function to call when conversion is complete
 */
function _arrayBufferToString(buf, callback) {
  var bb = new Blob([new Uint8Array(buf)]);
  var f = new FileReader();
  f.onload = function(e) {
    callback(e.target.result);
  };
  f.readAsText(bb);
}

对于香草,浏览器端,从麦克风录音,base64函数为我工作(我必须实现一个音频发送功能到聊天)。

      const ui8a =  new Uint8Array(e.target.result);
      const string = btoa(ui8a);
      const ui8a_2 = atob(string).split(',');

现在是完整代码。感谢Bryan Jennings & breakspirit@py4u.net提供的代码。

https://medium.com/@bryanjenningz/how-to-record-and-play-audio-in-javascript-faa1b2b3e49b

https://www.py4u.net/discuss/282499

index . html

<html>
  <head>
    <title>Record Audio Test</title>
    <meta name="encoding" charset="utf-8" />
  </head>
  <body>
    <h1>Audio Recording Test</h1>
    <script src="index.js"></script>
    <button id="action" onclick="start()">Start</button>
    <button id="stop" onclick="stop()">Stop</button>
    <button id="play" onclick="play()">Listen</button>
  </body>
</html>

index.js:

const recordAudio = () =>
  new Promise(async resolve => {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    const mediaRecorder = new MediaRecorder(stream);
    const audioChunks = [];

    mediaRecorder.addEventListener("dataavailable", event => {
      audioChunks.push(event.data);
    });

    const start = () => mediaRecorder.start();

    const stop = () =>
      new Promise(resolve => {
        mediaRecorder.addEventListener("stop", () => {
          const audioBlob = new Blob(audioChunks);
          const audioUrl = URL.createObjectURL(audioBlob);
          const audio = new Audio(audioUrl);
          const play = () => audio.play();
          resolve({ audioBlob, audioUrl, play });
        });

        mediaRecorder.stop();
      });

    resolve({ start, stop });
  });

let recorder = null;
let audio = null;
const sleep = time => new Promise(resolve => setTimeout(resolve, time));

const start = async () => {
  recorder = await recordAudio();
  recorder.start();
}

const stop = async () => {
  audio = await recorder.stop();
  read(audio.audioUrl);
}

const play = ()=> {
  audio.play();
}

const read = (blobUrl)=> {

  var xhr = new XMLHttpRequest;
  xhr.responseType = 'blob';
  
  xhr.onload = function() {
      var recoveredBlob = xhr.response;
      const reader = new FileReader();
      // This fires after the blob has been read/loaded.
      reader.addEventListener('loadend', (e) => {

          const ui8a =  new Uint8Array(e.target.result);
          const string = btoa(ui8a);
          const ui8a_2 = atob(string).split(',');
          
          playByteArray(ui8a_2);
      });
      // Start reading the blob as text.
      reader.readAsArrayBuffer(recoveredBlob);
  };
  // get the blob through blob url 
  xhr.open('GET', blobUrl);
  xhr.send();
}

window.onload = init;
var context;    // Audio context
var buf;        // Audio buffer

function init() {
  if (!window.AudioContext) {
      if (!window.webkitAudioContext) {
          alert("Your browser does not support any AudioContext and cannot play back this audio.");
          return;
      }
        window.AudioContext = window.webkitAudioContext;
    }

    context = new AudioContext();
}

function playByteArray(byteArray) {

    var arrayBuffer = new ArrayBuffer(byteArray.length);
    var bufferView = new Uint8Array(arrayBuffer);
    for (i = 0; i < byteArray.length; i++) {
      bufferView[i] = byteArray[i];
    }

    context.decodeAudioData(arrayBuffer, function(buffer) {
        buf = buffer;
        play2();
    });
}

// Play the loaded file
function play2() {
    // Create a source node from the buffer
    var source = context.createBufferSource();
    source.buffer = buf;
    // Connect to the final output node (the speakers)
    source.connect(context.destination);
    // Play immediately
    source.start(0);
}