Filesaver.js: 如何写入包含二进制数据的 blob?

Filesaver.js: how to write a blob containing binary data?

我想使用 fileSaver.js 单击按钮并保存 二进制 blob(类型:“application/octet-stream”)。 但我不知道如何按照我需要的方式保存 blob。

最终文件 (example.mod) 需要具有以下顺序:

我找到了一些保存“text/plain”或“image/png”的示例,但我无法弄清楚如何在我的案例中应用。

我已经制作了这个 CodePen 来展示我正在尝试做的事情,但是生成的文件不是预期的! 它 returns 一个这样的文件(所有信息都像文本文件一样可见):

8<POINTS>3A,10.5,10,10B,20,10,0.7C,10,20.3,109</POINTS>

...但是我想要得到的是用字节写的文件,像这样(在文本编辑器中查看时):

...或者当它作为 ArrayBuffer 读取时,我应该得到类似这样的结果:

Int8Array(119)[
    0: 0
    1: 0
    2: 0
    3: 8
    4: 60
    5: 80
    6: 79
    7: 73
    8: 78
    9: 84
    10: 83
    11: 62
    12: 3
    13: 0
    14: 0
    15: 0
    16: 2
    17: 0
    18: 0
    19: 0
    20: 1
    21: 65
    22: 0
    23: 0
    24: 0
    25: 0
    26: 0
    27: 0
    28: 37
    29: 64
    30: 0
    31: 0
    32: 0
    33: 0
    34: 0
    35: 0
    36: 36
    37: 64
    38: 0
    39: 0
    40: 0
    41: 0
    42: 0
    43: 0
    44: 36
    45: 64
    46: 2
    47: 0
    48: 0
    49: 0
    50: 1
    51: 66
    52: 0
    53: 0
    54: 0
    55: 0
    56: 0
    57: 0
    ​​58: 52
    ​​59: 64
    ​​60: 0
    ​​61: 0
    ​​62: 0
    ​​63: 0
    ​​64: 0
    65: 0
    66: 36
    ​​67: 64
    ​​68: 102
    ​​69: 102
    ​​70: 102
    ​​71: 102
    72: 102
    ​​73: 102
    ​​74: -26
    ​​75: 63
    76: 2
    77: 0
    ​​78: 0
    79: 0
    ​​80: 1
    ​​81: 67
    ​​82: 0
    ​​83: 0
    ​​84: 0
    ​​85: 0
    ​​86: 0
    87: 0
    ​​88: 36
    ​​89: 64
    ​​90: -51
    ​​91: -52
    ​​92: -52
    ​​93: -52
    ​​94: -52
    ​​95: 76
    96: 52
    ​​97: 64
    98: 0
    ​​99: 0
    100: 0
    ​​101: 0
    ​​102: 0
    ​​103: 0
    ​​104: 36
    105: 64
    ​​106: 0
    107: 0
    108: 0
    ​​109: 9
    ​​110: 60
    ​​111: 47
    ​​112: 80
    ​​113: 79
    ​​114: 73
    ​​115: 78
    ​​116: 84
    ​​117: 83
    ​​118: 62
]

PS:如果您知道如何在不使用 filesaver.js 的情况下获得这些结果,那对我也有用。

任何帮助将不胜感激!

谢谢。

已解决:

在挖掘了一段时间后,在不同的问题中发现了我需要整理出一个解决方案的点点滴滴(不确定这是否是最佳实践,但正在发挥作用!)

首先,我必须以不同的方式处理各种输入(字符串、数字(正整数)、数字(带符号的浮点实数)以匹配我在文件中需要的格式。

*1: 从这里得到了 StingToArrayBuffer 解决方案

//string to ArrayBuffer
function str2ab(str) {
  var buf = new ArrayBuffer(str.length); // 2 bytes for each char
  var bufView = new Uint8Array(buf);
  for (var i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  var result = new Uint8Array(bufView.buffer);
  return result;
}

*2: 从那个答案中得到了 numberToArrayBuffer 解决方案,修改为我的需要!

//.............number to ArratBuffer //*2
//integer To ArrayBuffer - 4 bits
function int2ArrBuf(value) {
  const view = new DataView(new ArrayBuffer(4))
  for (var index = 3; index >= 0; --index) {
    view.setUint8(index, value % 256)
    value = value >> 8;
  }
  var int = new Uint8Array(view.buffer);
  return int
}

//Reverse order
function Xint2ArrBuf(value) {
  const view = new DataView(new ArrayBuffer(4))
  for (var index = 0; index <= 3; ++index) {
    view.setUint8(index, value % 256)
    value = value >> 8;
  }
  var int = new Uint8Array(view.buffer);
  return int
}
//......................

//one bit long integer
function strsize(value) {
  const view = new DataView(new ArrayBuffer(1))
  
    view.setUint8(0, value % 256)
    value = value >> 8;
 
  var result= new Uint8Array(view.buffer);
  return result
}

从这个开始,图解如何保存点坐标

//point To ArrayBuffer - 3x 8 bits
function Pt2ArrBuf(x,y,z){
  var float32 = new Float32Array(3);
  float32[0] = x;
  float32[1] = y;
  float32[2] = z;

  var f = new Float64Array(float32);
  var pt = new Int8Array(f.buffer);  
  
  return pt;
}

*4: 准备数据序列并连接 TypedArrays

//here I write the file the way i Need it to be...

const binaryData = [
    int2ArrBuf(9),
    strsize(8),
    str2ab('<POINTS>'),
    int2ArrBuf(3),
    Xint2ArrBuf(2),
    strsize(1),
    str2ab('A'),
    Pt2ArrBuf(10.5,10,10),
    Xint2ArrBuf(2),
    strsize(1),
    str2ab('B'),
    Pt2ArrBuf(-20,10,0.7),
    int2ArrBuf(10),
    strsize(9),
    str2ab('</POINTS>') 
  ];

//here I join the many TypedArrays into one...
const mergedInt8Array = new Int8Array(binaryData.map(typedArray => [...new Int8Array(typedArray.buffer)]).flat());
console.log(mergedInt8Array);

*5: 来自 David 的 Codepen

blob 语法更正

//*5:direct download via FileSaver.js
var SaveButton = document.getElementById('save');
SaveButton.addEventListener('click', function () {
  var filename = document.getElementById("name").value;
  filename += '.txt';
  var blob = new Blob([mergedInt8Array], { type: "application/octet-stream"}); //*6
  saveAs(blob, filename);
});

这是 Codepen 的解决方案。谢谢。