4

我正在尝试将文件中的图像数据作为 base64 字符串存储到 PostgreSQL 数据库中,该字符串由 gzip 压缩以节省空间。我正在使用以下代码对图像进行编码:

@file = File.open("#{Rails.root.to_s}/public/" << @ad_object.image_url).read
@base64 = Base64.encode64(@file)
@compressed = ActiveSupport::Gzip.compress(@base64)
@compressed.force_encoding('UTF-8')
@ad_object.imageData = @compressed

当我尝试保存对象时,出现以下错误:

ActiveRecord::StatementInvalid (PG::Error: ERROR:  invalid byte sequence for encoding "UTF8": 0x8b

在 rails 控制台中,任何 gzip 压缩都会将数据输出为 ASCII 8 位编码。我尝试将我的内部和外部编码设置为 UTF-8,但结果没有改变。如何将此压缩数据转换为 UTF-8 字符串?

4

1 回答 1

5

由于多种原因,这没有多大意义。

  1. gzip 是二进制编码。绝对没有必要对某些东西进行 base64 编码然后对其进行 gzip 压缩,因为输出是二进制的,而 base64 仅用于通过非 8bit-clean 协议进行传输。直接gzip文件就行了。

  2. 大多数图像数据已经使用 PNG 或 JPEG 等编解码器进行压缩,在图像数据压缩方面比 gzip 更有效。压缩它通常会使图像稍微大一点。对于图像数据,Gzip 永远不会像 loss-les PNG 格式那样高效,因此如果您的图像数据未压缩,PNG 会压缩它而不是 gzip 压缩它。

  3. 当表示二进制数据时,实际上并没有文本编码问题,因为它不是文本。它不是有效的 utf-8,试图告诉系统它是有效的只会导致进一步的问题。

完全取消 base64 编码和 gzip 步骤。正如 mu 太短所说,只需使用 Railsbinary字段,让 Rails 处理二进制数据的编码和发送。

只需使用bytea数据库中的字段并直接存储 PNG 或 JPEG 图像。这些在传输线上进行了十六进制编码,占用了二进制空间的 2 倍,但它们以二进制形式存储在磁盘上。如果从压缩中受益, PostgreSQL 会自动压缩bytea磁盘上的字段,但大多数图像数据不会。

要最小化图像的大小,请选择适当的压缩格式,例如PNG无损压缩或JPEG照片。在压缩之前尽可能多地对图像进行下采样,并使用产生可接受质量的最强压缩(对于 JPEG 等有损编解码器)。不要尝试使用 gzip/LZMA/etc 进一步压缩图像,它会一事无成。

当十六进制转义通过网络传输时,您的数据仍然会增加一倍。解决这个问题需要使用 PostgreSQL 二进制协议(困难且复杂)或二进制干净的边带来传输图像数据。如果 Pg gem 支持 SSL 压缩,您可以使用它来压缩协议流量,这将大大降低hex转义的成本。

如果需要将大小保持在绝对最小值,我不会使用 PotsgreSQL 有线协议将图像发送到设备。它专为性能和可靠性而设计,而不是绝对最小尺寸。

于 2012-10-30T00:14:42.517 回答