概述: 我在网页中构建了一个Javascript工具。除了加载该页面外,该工具将在没有服务器通信的情况下运行。用户将选择包含多个二进制记录的本地文件,每个记录具有x< F0起始字节和x' F0结束字节。其间的数据限制在x&00; 00 - x' 7F,包括:
记录长度不同,使用不同的格式。 [它是一组MIDI Sysex消息,可能不相关]。 通过reader.readAsArrayBuffer读取本地文件,然后进行处理:
var contents = event.target.result;
var bytes = new Uint8Array(contents);
var rawAccum = '';
for (x = 0; x < bytes.length; x++) {
rawAccum += bytes[x];
}
var records = rawAccum.split(/\xF0/g);
我希望将字符串拆分为其组成记录的数组,删除进程中的x&#39; F0起始字节。 它实际上做得很少。 records.length为1,records [0]包含整个输入流。
[实际的分割代码是:var records = rawAccum.split(/ \ xF0 \ x00 \ x00 \ x26 \ x02 / g);应从每条记录的开头删除几个相同的字节。当这次失败时,我尝试了上面的缩写版本,结果相同(非)。]
我已经查看了有关拆分的文档(以及正则表达式引用中对\ xXX的几种解释。显然,某些内容不能像我推断的那样起作用。我使用JavaScript的经验很少且是零星的。
如何在出现特定二进制字节时拆分一串二进制数据?
答案 0 :(得分:0)
拆分似乎工作正常:
var rawAccum = "\xf0a\xf0b\xf0c\xf0"
console.log( rawAccum.length); // 7
var records = rawAccum.split(/\xF0/g);
console.log(records); // "", "a", "b", "c", ""
但是将数组缓冲区转换为字符串看起来很可疑。尝试将无符号字节值转换为字符串,然后将其附加到rawAccum
:
for (x = 0; x < bytes.length; x++) {
rawAccum += String.fromCharCode( bytes[x]);
}
<小时/> 数据转换(评论后更新)
文件读取器将文件读入内存中的数组缓冲区,但JavaScript不能直接访问数组缓冲区。您可以从缓冲区创建和初始化类型化数组(例如,使用文章中的Uint8Array构造函数),或使用DataView
object访问缓冲区中的字节。 DataView
对象的方法可以将指定位置的字节序列转换为不同类型的整数,例如Midi sysex记录中的16位整数。
JavaScript字符串使用16位值的序列来保存字符,其中每个字符使用一个或两个使用UTF-16字符编码编码的16位值。 8位字符仅使用单个16位值的低8位来存储其Unicode代码点。
通过将缓冲区中的每个字节值存储在16位字符的低位中并将其附加到现有字符串,可以将八位位组值的数组缓冲区转换为“二进制字符串”。这就是帖子试图做的事情。但是在JavaScript字符串中(以及字符串长度为1的单个字符)不是整数的子集,并且有自己的数据类型,“string”。
因此,要将无符号8位数转换为类型为“string”的JavaScript 16位字符,请使用全局fromCharCode
对象的String
静态方法,如
rawAccum += String.fromCharCode( bytes[x]);
调用String.fromCharCode
也是如何将MIDI数据中的ASCII字符代码转换为JavaScript中的字符。
要将从8位值派生的二进制字符串字符转换回数字,请对字符串值使用String实例方法charCodeAt
并提供字符位置:
var byteValue = "\xf0".charCodeAt(0);
返回数字0xf0或250十进制。
如果在字符串中附加一个数字,就像在问题中一样,该数字首先隐式转换为其值的十进制字符串表示形式:
"" + 0xf0 + 66 // becomes the string "24066"
<小时/> 请注意,可以使用从其创建的Uint8Array检查数组缓冲区,使用缓冲区的
slice
方法将其切片,并使用数据视图从缓冲区中提取各种类型的整数。请查看创建二进制字符串是否仍然是提取和解释Midi记录内容的最佳方式。