如何在Javascript/NodeJS中按字节解析Sierra Chart的.scid格式文件
scid文件解析问题排查与实现方案
现有代码的核心问题
- 逐字节读取并输出单字节十进制值,无法直接对应多字节组合的数值类型(int64、float32等),你看到的字节差异是拆分后的单字节表现,不是完整时间值的差异
- 没有利用Node.js Buffer内置的端序转换方法,手动拼接字节效率极低且容易出错
正确实现逻辑
首先明确格式核心规则:文件采用小端字节序(Little Endian),文件头占56字节可跳过,后续每个K线数据块固定40字节,结构如下:
| 字节偏移 | 类型 | 含义 |
|---|---|---|
| 0-7 | 无符号64位整数 | 时间戳(Windows FILETIME格式,单位100纳秒,基准为1601-01-01) |
| 8-11 | 32位浮点数 | 开盘价 |
| 12-15 | 32位浮点数 | 最高价 |
| 16-19 | 32位浮点数 | 最低价 |
| 20-23 | 32位浮点数 | 收盘价 |
| 24-27 | 无符号32位整数 | 成交量 |
后续字段可按官方规范按需补充解析。
修正后的Node.js实现代码
const fs = require('fs'); // FILETIME转JS Date工具方法 const filetimeToDate = (filetimeBigInt) => { // FILETIME转Unix时间戳:100纳秒单位转毫秒,减去1601到1970的毫秒差 const unixTimeMs = Number((filetimeBigInt / 10000n) - 11644473600000n); return new Date(unixTimeMs); }; fs.open('E://SierraChart/Data/hood.scid', 'r', (err, fd) => { if (err) throw err; // 跳过56字节文件头 const skipHeaderBuffer = Buffer.alloc(56); fs.readSync(fd, skipHeaderBuffer, 0, 56, 0); // 每次读取40字节完整K线块 const klineBuffer = Buffer.alloc(40); let readOffset = 56; // 从文件头后开始读 while (true) { const bytesRead = fs.readSync(fd, klineBuffer, 0, 40, readOffset); if (bytesRead !== 40) break; // 读完退出 // 按小端规则解析每个字段 const timestamp = filetimeToDate(klineBuffer.readBigUInt64LE(0)); const open = klineBuffer.readFloatLE(8); const high = klineBuffer.readFloatLE(12); const low = klineBuffer.readFloatLE(16); const close = klineBuffer.readFloatLE(20); const volume = klineBuffer.readUInt32LE(24); // 输出解析结果 console.log({ time: timestamp.toISOString(), open, high, low, close, volume }); readOffset += 40; } fs.closeSync(fd); });
时间差异疑问解释
你之前看到的多个数据块前8字节的后4个字节完全一致,是因为1分钟的时间差对应的FILETIME数值变化只有6e8(60秒 * 1e7 100纳秒单位),仅改动低4字节的部分位,高4字节完全不变。将8字节拼接为完整的64位整数后,就能看到相邻块的时间差正好是1分钟,符合你对时间粒度的预期。
内容的提问来源于stack exchange,提问作者Dat Tau
相关产品推荐
相关产品推荐

