存储大量超大整数的最省空间存储方案咨询
我有大量远超unsigned long long范围的超大整数,例如:
976790216313803691633662
213166167
12361374472474414331778521
74143614714316467475274141141343747437542416477224365045416
...
46247285274316436417475827426432634528582016257012061846140147206
7287516801860168175715895175371357381735188912758511
目前尝试过转字节存H5文件、numpy存.npz格式,压缩效果最好的是存为纯文本后打包成.tar.gz。想知道有没有压缩效果更好的方案?单文件行数范围在104到1012之间。
补充:可通过以下Python代码生成测试用整数列表:
import numpy as np def generate_int(n): return int(str(np.random.randint(1, 10)) + ''.join([str(np.random.randint(0, 10)) for _ in range(n-1)])) output = [generate_int(np.random.randint(4, 1001)) for _ in range(1000000)]
更优存储方案推荐
1. 变长二进制编码+高效压缩(最优压缩比)
纯文本存储每个数字占1字节ASCII,而二进制存储超大整数能大幅减少原始体积(比如100位数字的文本占100字节,二进制仅需约13字节),配合比gzip更高效的压缩算法(如lzma/zstd),能获得远高于文本+tar.gz的压缩效果。
实现示例(Python)
import lzma import struct def save_bigints(int_list, filename): # 用lzma最高压缩级别,也可替换为zstd提升速度 with lzma.open(filename, 'wb', preset=9) as f: for num in int_list: # 将整数转为大端字节流 byte_len = (num.bit_length() + 7) // 8 byte_data = num.to_bytes(byte_len, byteorder='big') # 先写入字节长度(4字节无符号整数,足够覆盖1000位整数的字节数) f.write(struct.pack('>I', byte_len)) f.write(byte_data) def load_bigints(filename): int_list = [] with lzma.open(filename, 'rb') as f: while True: len_buf = f.read(4) if not len_buf: break byte_len = struct.unpack('>I', len_buf)[0] byte_data = f.read(byte_len) num = int.from_bytes(byte_data, byteorder='big') int_list.append(num) return int_list
优势:原始体积比文本小70%以上,加上lzma的高压缩比,最终文件体积通常是文本+tar.gz的30%-50%;若用zstd,压缩速度更快,压缩比接近lzma。
2. HDF5+可变长度字节数组+高压缩(适合大数据量随机访问)
之前用HDF5效果不佳,大概率是因为错误尝试用numpy数值类型存储超大整数(numpy不支持)。正确做法是将每个整数转为字节数组,存储为HDF5的可变长度字节数据集,并开启lzma/zstd压缩,既保留HDF5的分块存储、随机访问能力,又能获得接近纯二进制压缩的效果。
实现示例(Python)
import h5py def save_bigints_h5(int_list, filename): with h5py.File(filename, 'w') as f: # 转换所有整数为字节数组 byte_arrays = [num.to_bytes((num.bit_length() + 7) // 8, byteorder='big') for num in int_list] # 创建带lzma最高压缩的可变长度字节数据集 dset = f.create_dataset( 'bigints', data=byte_arrays, dtype=h5py.special_dtype(vlen=bytes), compression='lzma', compression_opts=9, chunks=True # 分块存储,适合超大数据量 ) def load_bigints_h5(filename): int_list = [] with h5py.File(filename, 'r') as f: for byte_data in f['bigints']: num = int.from_bytes(byte_data, byteorder='big') int_list.append(num) return int_list
优势:支持随机读取指定位置的整数,适合10^12行级别的超大数据量,压缩效果接近纯二进制方案,仅多少量HDF5元数据开销。
3. 文本+xz/zstd压缩(次优方案,兼容文本场景)
如果必须保留文本格式,用xz(lzma算法)或zstd替换gzip,压缩比会显著提升。例如用xz -9压缩文本文件,体积比tar.gz小20%-40%。
方案对比
| 方案 | 压缩比 | 速度 | 随机访问 | 适合场景 |
|---|---|---|---|---|
| 二进制+lzma | 最高 | 慢 | 不支持 | 追求最小体积,批量读写 |
| 二进制+zstd | 很高 | 快 | 不支持 | 平衡压缩比与速度,批量读写 |
| HDF5+lzma | 很高 | 中 | 支持 | 超大数据量,需随机访问 |
| 文本+xz | 较高 | 中 | 支持 | 需兼容文本工具,压缩比优于gz |
| 文本+tar.gz | 一般 | 中 | 支持 | 通用兼容,但压缩比一般 |
内容的提问来源于stack exchange,提问作者John

