【发布时间】:2018-09-08 08:29:17
【问题描述】:
经过数小时的不确定研究和测试,我想我会问:
简介
我正在尝试将非常大的Doubles 数组从应用程序发送到服务器,当然,我想尽可能地压缩它。
具体来说,这些数组包含CMDeviceMotion 组件(加速度、x、y、z、陀螺仪等...),但这个问题应该适用于任何大型数字数组(超过 100K 或一百万个值)
我通过研究选项尝试并发现了什么
假设我有一大堆Double(还有很多其他的):
var CMX = CM.map({$0.userAcceleration.x})
这里,CMX 是 [Double] 类型,CM 是 [CMDeviceMotion]
我尝试通过以不同方式发送CMX 向我的服务器发出POST 请求,然后在我在服务器上收到它后计算总大小:
- 首先,作为一个逗号分隔的字符串:
{"AX":"-0.0441827848553658,-0.103976868093014,-0.117475733160973,-0.206566318869591,-0.266509801149368,-0.282151937484741,-0.260240525007248,-0.266505032777786,-0.315020948648453,-0.305839896202087,0.0255246963351965,0.0783950537443161,0.0749507397413254,0.0760494321584702,-0.0101579604670405,0.106710642576218,0.131824940443039,0.0630970001220703,0.21177926659584,0.27022996544838,0.222621202468872,0.234281644225121,0.288497060537338,0.176655143499374,0.193904414772987,0.169417425990105,0.150193274021149,0.00871349219232798,-0.0270088445395231,-0.0 ....
大小 153 KB。
这比作为二进制数据发送更大是有道理的,因为这里的单个数字是 64 位(8 个字节),并且变成 17 个字节长(每个字符一个字节)+1 = 18(为逗号)。
根据这个推理,将数组作为二进制数据发送应该更小。
- Base 64 编码
在这里,我使用NSKeyedArchiver 将数组转换为Data 对象,并在发送数据之前对数据进行base 64 编码:
["AX":NSKeyedArchiver.archivedData(withRootObject:CM.map({$0.userAcceleration.x})).base64EncodedString()]
这使得文件大小为 206 Kb
- 以 JSON 数组形式发送数据
只需发送:
["AX": CM.map({$0.userAcceleration.x})]
事实证明,这个数字数组实际上被转换为逗号分隔的字符串,大小最终与试验 1 中的相同(160Kb)
- 以
Data发送,不使用base 64 编码
这样做:
["AX":NSKeyedArchiver.archivedData(withRootObject:CM.map({$0.userAcceleration.x}))
使应用程序在运行时崩溃,因此我无法将 Data 对象作为 JSON 中的值发送
问题
如何在 JSON 对象中以更简洁的方式发送这些数组?
请注意,我已经考虑过下采样,并使用 32 位浮点数来减小大小。
【问题讨论】:
-
您可以尝试压缩数据字符串,然后将其发送 base64 编码,或者尝试获取 Double 的二进制表示形式(如这里:stackoverflow.com/questions/26953591/…)并将其发送 base64 编码
-
任何压缩方法都需要了解数据的潜在模式。例如数据范围、顺序是否重要、固定十进制数等。