Ruby:将二进制字符串转换为IO

7

我有一串二进制数据,需要将其作为IO对象使用。因此,我尝试了以下代码:

r, w = IO.pipe()
w << data

但是它失败了,出现了以下错误:
Encoding::UndefinedConversionError ("\xD0" from ASCII-8BIT to UTF-8)

为什么它首先要转换为UTF-8?有没有一种方法可以强制IO::pipe方法进入二进制模式?

更多细节:

我正在尝试使用Mongoid驱动程序从MongoDB读取二进制数据(即Excel文件),然后将其转换为IO对象以便使用Spreadsheet gem读取它。 Spreadsheet#open要求提供文件路径或IO对象。

这是我的文件文档的样子:

class ImportedFile
    include Mongoid::Document

    field :file_name, type: String
    field :binary_content, type: Moped::BSON::Binary
end

以下是我保存二进制数据的方法:

imported_file = ImportedFile.new
imported_file.file_name = uploaded_file.original_filename
imported_file.binary_content = Moped::BSON::Binary.new(:generic, uploaded_file.read)
imported_file.save

以下是我尝试阅读它的方式(不起作用):

imported_file = ImportedFile.find(file_id)

r, w = IO.pipe()
w << imported_file.binary_content.data
book = Spreadsheet.open r
2个回答

6
你可以使用 StringIO 来实现这个功能:
require 'stringio'

io = StringIO.new(binary_data)
book = Spreadsheet.open(io)

1
不要使用原始的StringIO处理二进制数据。我发现没有人在实际环境中测试过StringIO。
bin = ["d9a1a2"].pack("H*")
puts bin.encoding
puts bin[0].unpack("H*")
puts "----"

io = StringIO.new bin
puts io.string.encoding
puts io.string[0].unpack("H*")
puts "----"

io = StringIO.new
io << bin
puts io.string.encoding
puts io.string[0].unpack("H*")
io.string.force_encoding Encoding::BINARY
puts io.string.encoding
puts io.string[0].unpack("H*")
puts "----"

io = StringIO.new
io.binmode
io << bin
puts io.string.encoding
puts io.string[0].unpack("H*")
io.string.force_encoding Encoding::BINARY
puts io.string.encoding
puts io.string[0].unpack("H*")
puts "----"

io = StringIO.new
io.set_encoding Encoding::BINARY
io << bin
puts io.string.encoding
puts io.string[0].unpack("H*")
puts "----"

ruby-2.3.3

ASCII-8BIT
d9
----
ASCII-8BIT
d9
----
UTF-8
d9a1
ASCII-8BIT
d9
----
ASCII-8BIT
d9
ASCII-8BIT
d9
----
ASCII-8BIT
d9
----

rbx-3.72

ASCII-8BIT
d9
----
ASCII-8BIT
d9
----
UTF-8
d9a1
ASCII-8BIT
d9
----
UTF-8
d9a1
ASCII-8BIT
d9
----
ASCII-8BIT
d9
----

jruby-9.1.7.0

ASCII-8BIT
d9
----
ASCII-8BIT
d9
----
UTF-8
d9a1
ASCII-8BIT
d9
----
UTF-8
d9a1
ASCII-8BIT
d9
----
ASCII-8BIT
d9
----
  1. 永远不要使用原始的 StringIO
  2. 不要相信 binmode。它不仅仅是针对 MRI 的存根。
  3. 使用 io.set_encoding Encoding::BINARYio.string.force_encoding Encoding::BINARY

io.set_encoding Encoding::BINARY 仍然是在MRI 3.0.1中的一个好的解决方案。 - Wayne Conrad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接