在Ruby中将多个输入源连接为单个IO对象

iswrvxsc  于 2022-12-12  发布在  Ruby
关注(0)|答案(1)|浏览(160)

bounty将在2天后过期。回答此问题可获得+200声望奖励。ndnenkov正在寻找标准答案:对于应该存在于代码库中的内容,没有提供答案。

我有一个输入源集合--字符串、文件等--我希望将它们连接起来并传递给一个API,该API期望从单个IO对象中读取数据。(~10 GB),所以将它们读入内存并将它们连接成单个字符串是不可行的。(我也考虑过使用IO.pipe,但增加额外的线程或进程似乎有些大材小用。)
在Ruby中是否有一个现有的库类来实现这个功能,参见Java的SequenceInputStream?如果没有,是否有其他方法可以直接和习惯地实现它?

jhdbpxl9

jhdbpxl91#

不幸的是,它正在使用IO.copy_stream写入套接字
要使IO::copy_stream(src, ...)正常工作,***src的类似IO的对象应该具有readpartialread方法。***
因此,让我们尝试定义一个类,它在一系列IO对象上实现IO#read

class ARGIO

  def initialize(*io)
    @array = io
    @index = 0
  end

  def read(maxlen = nil, out_string = (maxlen.nil? ? "" : String.new))
    out_string.clear
    if maxlen.nil?
      if @index < @array.count
        @array[@index..-1].each{|io| out_string.concat(io.read)}
        @index = @array.count
      end
    elsif maxlen >= 0
      while out_string.bytesize < maxlen && @index < @array.count
        bytes = @array[@index].read(maxlen - out_string.bytesize)
        if bytes.nil?
          @index += 1
        else
          out_string.concat(bytes)
        end
      end
      return nil unless out_string.bytesize
    end
    out_string
  end

end

**注意:**我没有深入研究规范的编码部分

现在,让我们将此类与IO::copy_stream一起使用:

require 'stringio'

io1 = StringIO.new(  "1")
io2 = StringIO.new( "22")
io3 = StringIO.new("333")
io4 = StringIO.new( "44")
io5 = StringIO.new(  "5")
io6 = StringIO.new( "66")
io7 = StringIO.new("777")
io8 = StringIO.new( "88")
io9 = StringIO.new(  "9")
io0 = StringIO.new( "\n")

argio = ARGIO.new(io1,io2,io3,io4,io5,io6,io7,io8,io9,io0)

IO.copy_stream(argio,STDOUT)

真管用!

12233344566777889

结论
因为没有gem,所以唯一合理的解决方法是确定API所需的IO方法,并编写一个实现这些方法的类。

**附言:**事实上,有一个multi_io gem可以将多个IO源连接到一个IO对象中,但是它的方法不符合规范;例如,不能将IO::copy_stream与它一起使用。

相关问题