需求:js 传输的 json 字符串里面有坐标数组,坐标数值都小于 4,096 。 尽可能压缩传输体积。
目前想法是 把 x,y 坐标直接 (x<<16)|y
聚集成一个 int32 值,刚好 4 个字节对应 utf8 4 个字节,然而有很多字符都没对应的,所以无法一一转化.
用的是 websocket 传输,虽然支持 arrayBuffer 类型,但是我的数据都是字符串格式的,还有其他信息要一起。
大佬们有什么方案吗?把坐标压缩到字符串里面节省空间
1
lasuar 2021-09-16 16:23:58 +08:00
我有个问题,你这个 (x<<16)|y 操作可逆吗? 另外,你要节省就直接传 binary,别整 json 。
|
2
JustLookBy OP |
3
zjsxwc 2021-09-16 16:34:08 +08:00
压缩 json 用这个库不行吗?
https://github.com/rgcl/jsonpack |
4
chenluo0429 2021-09-16 16:35:23 +08:00 1
比如对于坐标 2423,2342,使用坐标字符串是{"point":"2423,2342"},转换成 int32 是{"point":158796070},数字转成 36 进制存储是{"point":"2mjjty"}。基本上省了个寂寞。
想要压缩就用 protobuf, flatbuffer, kiwi 这些,不要用 json |
5
chendy 2021-09-16 16:36:07 +08:00 3
必须字符串的话
用 base64 的码表做 64 进制表示,然后全部拼进一个字符串里,两个字符是一个数字,四个字符是一个坐标,接收方自己解析成坐标数组就行 |
6
chenluo0429 2021-09-16 16:37:53 +08:00
一定要用 json,你还不如把字段名精简一下,可能比你折腾数字优化得还多些
|
7
jifengg 2021-09-16 16:44:23 +08:00
不知道你的“字符串里面有坐标数组”具体是什么格式,如果数字多的话,自定义一个二进制格式,传输之前 zip 压缩一下。
json 是格式统一方便应用解析,要尽可能节省的话用二进制+压缩。压缩会耗 CPU 可以酌情考虑加不加。 |
8
zjsxwc 2021-09-16 16:46:26 +08:00
而且 js 里整数存储比较奇葩,与主流语言使用 64 位存整数不同,js 是用 54 位来存储整数的。
在 js 中当然不存在 int32 了。 当然和楼主的需求不一样,因为用了 json 文本格式传输,楼主应该是想用字符表示上短一点数字, 我觉得可以先按楼主的算法两个数字变成一个数字,然后这个数字再用 36 进制表示,然后对 json 文本进行 jsonpack 压缩。 逃 |
9
smartbot 2021-09-16 16:46:37 +08:00 1
protobuf, 应该是一种可选数据格式。
|
10
JustLookBy OP |
11
littlewing 2021-09-16 16:52:38 +08:00
ISO-8859-1
|
12
masterclock 2021-09-16 16:54:01 +08:00
1. 选择 CBOR 格式传输
2. 如果时大量数据,加压缩 |
13
chendy 2021-09-16 16:54:13 +08:00
@JustLookBy 但是相比于直接用数字已经砍掉一半了,还去掉了一堆逗号
|
14
zjsxwc 2021-09-16 16:57:50 +08:00
protobuf 应该是最省带宽
|
15
lasuar 2021-09-16 17:12:35 +08:00
@JustLookBy 行,位运算玩的挺溜
|
16
Vegetable 2021-09-16 17:18:29 +08:00
认为这个没什么意义,哪怕是传 binary,也省不下来多少,更何况你还有别的内容,还不如上一层 gzip 。
|
17
learningman 2021-09-16 17:18:29 +08:00 via Android
感觉拿 gzip 压一下就差不多了吧。。。
|
18
2i2Re2PLMaDnghL 2021-09-16 18:48:37 +08:00 1
我都怀疑你是特地凑好的
64*64=4096 如果限定在 ASCII 内,则只有 94 个字符可供表示(从 0x20 到 0x7F 再去掉引号和反斜杠),用 base94 表示的话 log_94 4096 = 1.83 仍然是四个字符表示一个坐标,和 base64 没区别 如果拓宽到 unicode,鉴于 UCS-2 会导致其他部分全部翻倍,得不偿失,所以还是 UTF-8 这就有个问题,UTF-8 编码效率非常不稳定,甚至可能三字节表示一个码位,看你的分布了 压缩有压缩的工具。 |
19
2i2Re2PLMaDnghL 2021-09-16 18:59:05 +08:00
压缩可能比 protobuf 更少。
比如如果你一千个坐标里面有五百个是同一个坐标,压缩能减很多。 |
20
joesonw 2021-09-16 19:18:46 +08:00
const ab = new ArrayBuffer(4);
const view = new Uint16Array(ab); view[0] = x; view[1] = y; const socket = new WebSocket("ws://localhost:8080"); socket.binaryType = "arraybuffer"; socket.write(ab); |
21
xiangyuecn 2021-09-16 20:05:54 +08:00
存储前后坐标的差值,大概率能变成 0-9 的一位数,只需一个字符就能存储一个数字,2 个字符存储一个坐标,压缩比目测可以达到 30%
之前写过一套经纬度坐标的压缩+解压代码,支持 6 位小数精度,150 来行代码,欢迎围观 https://github.com/xiangyuecn/AreaCity-JsSpider-StatsGov/blob/master/assets/geo-echarts.js#L528-L707 |
22
also24 2021-09-16 20:07:16 +08:00
@learningman #17
我也觉得,反正都是重复字符,压缩效果应该很不错才对 |
23
elfive 2021-09-16 20:16:31 +08:00 via iPhone
数据压缩呀,lzma 压缩,我之前做的嵌入式程序,也是 json,也是传点坐标(两个 float,一般是上万个点),经过 lzma 压缩,能节约大概 80%的数据量。
|
24
JustLookBy OP |
25
ysc3839 2021-09-16 21:02:05 +08:00 via Android
允许换掉 JSON 的话改用 Msgpack 吧,和 JSON 兼容。
|
26
SmiteChow 2021-09-17 10:12:23 +08:00
msgpack
|