在F#中包含流中的序列

时间:2011-06-04 07:43:16

标签: f#

我有一个接受Stream的功能。我的数据位于一个大型列表中,运行数百万个项目。

有没有一种简单的方法可以在Stream中包装序列,在流中返回序列的块?一种显而易见的方法是实现我自己的流类,它返回序列的块。类似的东西:

type SeqStream(sequence:seq<'a>) = 
    inherit Stream()
    default x.Read(buf, offset, count) =
        // get next chunk
        // yield chunk

有更简单的方法吗?我没有办法改变接受流的目标函数。

1 个答案:

答案 0 :(得分:6)

我认为你的方法看起来不错。唯一的问题是Stream是一个相对复杂的类,有相当多的成员,你可能不想实现其中的大多数 - 如果你想将它传递给一些使用一些其他成员的代码,你需要使实现更复杂。无论如何,仅实现Read的简单流可以如下所示:

type SeqStream<'a>(sequence:seq<'a>, formatter:'a -> byte[]) =
  inherit Stream()

  // Keeps bytes that were read previously, but were not used    
  let temp = ResizeArray<_>() 
  // Enumerator for reading data from the sequence
  let en = sequence.GetEnumerator()

  override x.Read(buffer, offset, size) = 
    // Read next element and add it to temp until we have enough
    // data or until we reach the end of the sequence
    while temp.Count < size && en.MoveNext() do
      temp.AddRange(formatter(en.Current))

    // Copy data to the output & return count (may be less then 
    // required (at the end of the sequence)
    let ret = min size temp.Count
    temp.CopyTo(0, buffer, offset, ret)
    temp.RemoveRange(0, ret)
    ret

  override x.Seek(offset, dir) = invalidOp "Seek"
  override x.Flush() = invalidOp "Flush"
  override x.SetLength(l) = invalidOp "SetLength"
  override x.Length = invalidOp "Length"
  override x.Position 
    with get() = invalidOp "Position"
    and set(p) = invalidOp "Position"
  override x.Write(buffer, offset, size) = invalidOp "Write"
  override x.CanWrite = false
  override x.CanSeek = false
  override x.CanRead = true

请注意,我添加了一个附加参数 - 将泛型类型的值转换为字节数组的函数。通常,很难将任何东西转换为字节(你可以使用一些序列化),所以这可能更容易。例如,对于整数,您可以写:

let stream = new SeqStream<_>([ 1 .. 5 ], System.BitConverter.GetBytes)