You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

网页端JS工具:如何按特定二进制值拆分含二进制内容的字符串?

按特定二进制值拆分本地二进制文件内容(MIDI Syssex场景)

嘿,刚好做过类似的MIDI Syssex处理工具,给你梳理下正确的解决思路——千万别用字符串来处理二进制!这是踩过坑的教训😂。因为JS字符串是UTF-16编码的,直接处理二进制数据会出现编码丢失或乱码,必须用ArrayBuffer + Uint8Array来操作原始字节。

核心步骤说明

你的需求是拆分以0xF0作为首尾标识的二进制记录,每条记录内部数据都是0x00-0x7F,具体实现分为这几步:

1. 读取本地文件为原始二进制数据

用FileReader的readAsArrayBuffer方法读取文件,这样拿到的是未经编码转换的原始二进制缓冲区,完全保留每个字节的真实值。

2. 转换为Uint8Array方便字节级操作

把ArrayBuffer转成Uint8Array,就能直接遍历每个字节的数值(0-255),轻松定位0xF0分隔符。

3. 遍历拆分出每条Syssex记录

遍历Uint8Array,记录每个0xF0的位置:第一次遇到0xF0标记为记录起始,第二次遇到0xF0就截取从起始到当前位置的片段作为一条完整记录,然后重置起始标记继续处理下一条。

完整代码示例

<input type="file" id="syssexFileInput" accept=".syx,.bin">
<script>
document.getElementById('syssexFileInput').addEventListener('change', handleSyssexFileSelect);

function handleSyssexFileSelect(e) {
  const selectedFile = e.target.files[0];
  if (!selectedFile) return;

  const fileReader = new FileReader();
  fileReader.onload = function(loadEvent) {
    // 拿到原始二进制缓冲区
    const rawBuffer = loadEvent.target.result;
    // 转换为Uint8Array
    const byteArray = new Uint8Array(rawBuffer);
    // 拆分Syssex消息
    const syssexMessages = splitSyssexRecords(byteArray);
    
    // 处理每条拆分后的消息
    syssexMessages.forEach((msg, index) => {
      console.log(`第 ${index+1} 条Syssex消息(长度:${msg.length}字节)`, msg);
      // 可以在这里进一步解析消息内容:位图、数值、ASCII等
      parseSyssexContent(msg);
    });
  };
  // 以ArrayBuffer格式读取文件
  fileReader.readAsArrayBuffer(selectedFile);
}

function splitSyssexRecords(byteArray) {
  const records = [];
  let startPos = -1;

  for (let i = 0; i < byteArray.length; i++) {
    const currentByte = byteArray[i];
    if (currentByte === 0xF0) {
      if (startPos === -1) {
        // 标记一条记录的起始位置
        startPos = i;
      } else {
        // 标记记录结束,截取从start到当前位置(包含首尾两个0xF0)
        const currentRecord = byteArray.slice(startPos, i + 1);
        // 可以在这里加个校验:确保记录长度至少为2(首尾两个F0)
        if (currentRecord.length >= 2) {
          records.push(currentRecord);
        }
        // 重置起始位置,准备下一条记录
        startPos = -1;
      }
    }
  }

  // 处理文件末尾未结束的不完整记录
  if (startPos !== -1) {
    console.warn('检测到不完整的Syssex记录,已自动忽略');
  }

  return records;
}

function parseSyssexContent(syssexMsg) {
  // 跳过首尾的0xF0,获取核心内容
  const content = syssexMsg.slice(1, syssexMsg.length - 1);
  if (content.length === 0) return;

  // 解析位图(假设第一个字节是位图)
  const bitmap = content[0];
  console.log('位图(二进制):', bitmap.toString(2).padStart(8, '0'));
  
  // 解析1字节数值
  const singleByteValue = content[1];
  console.log('1字节数值:', singleByteValue);
  
  // 解析低字节在前的2字节数值
  if (content.length >=4) {
    const twoByteValue = content[2] + (content[3] << 8);
    console.log('2字节数值(低字节在前):', twoByteValue);
  }
  
  // 解析后续ASCII字符
  const asciiStr = Array.from(content.slice(4)).map(byte => String.fromCharCode(byte)).join('');
  console.log('ASCII内容:', asciiStr);
}
</script>

关键注意事项

  • 绝对不要用字符串处理二进制:比如readAsText会把二进制转成字符串,0xF0这类非UTF-8兼容字节会被替换成�,直接丢失数据。
  • 校验记录有效性:拆分后可以检查每条记录的首尾是否都是0xF0,过滤掉无效或不完整的记录。
  • 大文件兼容性:readAsArrayBuffer是异步操作,不会阻塞主线程,处理几百MB的文件也没问题。

内容的提问来源于stack exchange,提问作者Chris Beall

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:08:46