在 node.js 上将 float32array 保存到磁盘的紧凑方法是啥?

Posted

技术标签:

【中文标题】在 node.js 上将 float32array 保存到磁盘的紧凑方法是啥?【英文标题】:What is a compact way to save a float32array to disk on node.js?在 node.js 上将 float32array 保存到磁盘的紧凑方法是什么? 【发布时间】:2013-12-16 21:20:33 【问题描述】:

JSON.stringify 显然不节省空间。使用 Node.js 序列化和存储 float32array 最优雅的方法是什么?

编辑:人们关闭问题的原因是“基于意见”和“对问题缺乏了解”。我真的相信第一个是missclick。对于第二个,也许这更清楚:

var fs = require("fs");
var len = 1000*1000*10;
var big_array = new Float32Array(len);
for (var i=0; i<len; ++i)
    big_array[i] = Math.random();

// OBVIOUSLY NOT SPACE EFFICIENT \/
fs.writeFileSync("big_array.json",JSON.stringify(big_array));

它不节省空间,因为您将数字表示为字符串,因此 8 字节浮点数将使用多达 ~20 个 utf8 字符,这是一种浪费。问题是:如何以节省空间的方式存储数组?

【问题讨论】:

到目前为止你尝试过什么?说到序列化,什么是“优雅”? 将优雅理解为您应该制定的标准,就像 JSON.stringify 是序列化任意数据的预期方式一样。 关于您对关闭原因的编辑:当您要求“优雅”时,这会转化为意见。您是否尝试过保存数组的 buffer 属性?这只是字节。 也许使用buf.writeFloat*并将缓冲区保存到磁盘? 我对此也很感兴趣。我需要这个从节点存储并从浏览器中检索 Float32Array。我不能依赖 JSON,因为如果数组太大,比如 1M 的浮点值,它很容易达到很多 MB(例如,我刚刚尝试序列化一个 220k 值的数组,它被序列化为 2.3 的 JSON MB) 【参考方案1】:

最后我设法用nodejs将float32array写入磁盘并在浏览器上检索它们,希望对您有所帮助。

在 NodeJS 中将 Float32Array 写入二进制文件

    var fs = require('fs');
    var wstream = fs.createWriteStream('data.dat');

    var data = new Float32Array([1.1,2.2,3.3,4.4,5.5]);

    //prepare the length of the buffer to 4 bytes per float
    var buffer = new Buffer(data.length*4);


    for(var i = 0; i < data.length; i++)
        //write the float in Little-Endian and move the offset
        buffer.writeFloatLE(data[i], i*4);
    

    wstream.write(buffer);
    wstream.end();

读取文件并将其转换为浏览器上的 Float32Array

​​>
    var urlToFloatFile = 'data.dat';
    var request = new XMLHttpRequest();
    request.open('GET', urlToFloatFile, true);

    //specify the response type as arraybuffer
    request.responseType = 'arraybuffer';

    request.onload = function (msg)  
        var yourFloatData = new Float32Array(this.response);
        console.log(yourFloatData);
    ;
    request.send();

感谢来自 WebGL Dev List GGroup https://groups.google.com/forum/#!topic/webgl-dev-list/EbGUi_iSEx8 的 @ben_a_adams 的客户端代码

我创建了一个简单的测试来粗略地测试浮点数组的 JSON 序列化与二进制表示有多少空间不同,结果是:

2.000.000 个浮点值

二进制文件为 7.8MB

JSON 文件为 38.5MB

17.5 压缩 JSON 文件

【讨论】:

读取文件也可以使用fetch API 改进:gist.github.com/jpweeks/9ccbfdfbcf69babf2e745c3ae0cc45d4【参考方案2】:

实际上可能有一个更简单的版本

let fs = require('fs')
let data = [150, 180]
fs.writeFileSync('mydata', new Buffer(new Uint32Array(data).buffer))
fs.readFile('mydata', (err, buf) => 
    let restoredData = new Uint32Array(buf.buffer, buf.offset, buf.byteLength/4)
    console.log(data[1])
    console.log(restoredData[1])
);

【讨论】:

这看起来很棒【参考方案3】:

简单、干净的方法:

const float32Array = new Float32Array([.69,.420])
const buffer = Buffer.from(float32Array.buffer)
fs.writeFileSync(filePath, buffer)
const loadedBuffer = fs.readFileSync(filePath)
const newFloat32Array = new Float32Array(loadedBuffer.buffer)

【讨论】:

【参考方案4】:

我相信你可以使用 Meteor 的 EJSON:

http://docs.meteor.com/#ejson

https://npmjs.org/package/meteor-ejson

EJSON 是 JSON 的扩展,支持更多类型。它支持所有 JSON 安全类型,以及:

日期(javascript 日期) 二进制(JavaScript Uint8Array 或 EJSON.newBinary 的结果) 用户定义的类型(参见 EJSON.addType。例如,Meteor.Collection.ObjectID 就是这样实现的。)

【讨论】:

以上是关于在 node.js 上将 float32array 保存到磁盘的紧凑方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在Android上将arraybuffer从javascript传递到java?

在 Windows 上将 Node.js 的版本切换到 6.11.5

未安装 Node.js。在 Mac 上将 Amplify AWS 添加到 Android Studio

Node.js 和 JQuery:“ReferenceError:$ 未定义”错误。如何在服务器上将 jquery 与节点一起使用?

如何在 Node JS 上将 http 重定向到 https

在 Amazon Linux 2 上将 node.js 应用程序部署到 Elastic Beanstalk 时出错