加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Scala:读取枚举器[T]的一些数据并返回剩余的枚举器[T]

发布时间:2020-12-16 10:03:22 所属栏目:安全 来源:网络整理
导读:我正在使用playframework的异步I / O库,它使用Iteratees和Enumerators.我现在有一个Iterator [T]作为数据接收器(简化说它是一个Iterator [Byte],它将其内容存储到一个文件中).此迭代器[Byte]被传递给处理写入的函数. 但在编写之前我想在文件开头添加一些统计
我正在使用playframework的异步I / O库,它使用Iteratees和Enumerators.我现在有一个Iterator [T]作为数据接收器(简化说它是一个Iterator [Byte],它将其内容存储到一个文件中).此迭代器[Byte]被传递给处理写入的函数.

但在编写之前我想在文件开头添加一些统计信息(为简化说它是一个字节),所以我在将迭代器传递给write函数之前按以下方式传递:

def write(value: Byte,output: Iteratee[Byte]): Iteratee[Byte] =
    Iteratee.flatten(output.feed(Input.El(value)))

当我现在从磁盘读取存储的文件时,我得到了一个Enumerator [Byte].
首先,我想读取并删除其他数据,然后我想将其余的Enumerator [Byte]传递给处理读取的函数.
所以我还需要转换枚举器:

def read(input: Enumerator[Byte]): (Byte,Enumerator[Byte]) = {
   val firstEnumeratorEntry = ...
   val remainingEnumerator = ...
   (firstEnumeratorEntry,remainingEnumerator)
}

但我不知道如何做到这一点.如何从枚举器中读取一些字节并获取剩余的枚举器?

使用InputStream替换带有OutputStream和Enumerator [Byte]的Iteratee [Byte],这将非常简单:

def write(value: Byte,output: OutputStream) = {
    output.write(value)
    output
}
def read(input: InputStream) = (input.read,input)

但是我需要play框架的异步I / O.

解决方法

这是通过在Iteratee和一个适当的(种类)状态累加器(这里的元组)中折叠来实现此目的的一种方法

我去读路由文件,第一个字节将作为Char读取,另一个将作为UTF-8字节串附加到字符串.

def index = Action {
    /*let's do everything asyncly*/
    Async {
      /*for comprehension for read-friendly*/
      for (
        i <- read; /*read the file */
        (r:(Option[Char],String)) <- i.run /*"create" the related Promise and run it*/
      ) yield Ok("first : " + r._1.get + "n" + "rest" + r._2) /* map the Promised result in a correct Request's Result*/
    }
  }


  def read = {
    //get the routes file in an Enumerator
    val file: Enumerator[Array[Byte]] = Enumerator.fromFile(Play.getFile("/conf/routes"))

    //apply the enumerator with an Iteratee that folds the data as wished
    file(Iteratee.fold((None,""):(Option[Char],String)) { (acc,b) =>
       acc._1 match {
         /*on the first chunk*/ case None => (Some(b(0).toChar),acc._2 + new String(b.tail,Charset.forName("utf-8")))
         /*on other chunks*/ case x => (x,acc._2 + new String(b,Charset.forName("utf-8")))
       }
    })

  }

编辑

我发现了使用Enumeratee的另一种方法,但它需要创建2个枚举器(一个短暂的).但它更优雅一点.我们使用“种类”Enumeratee,但Traversal使用比Enumeratee(chunck级别)更精细的级别.
我们使用take 1只需1个字节然后关闭流.另一方面,我们使用drop来简单地删除第一个字节(因为我们使用的是Enumerator [Array [Byte]])

此外,现在read2的签名比你想要的更接近,因为它返回2个枚举器(距离Promise,Enumerator不远)

def index = Action {
  Async {
    val (first,rest) = read2
    val enee = Enumeratee.map[Array[Byte]] {bs => new String(bs,Charset.forName("utf-8"))}

    def useEnee(enumor:Enumerator[Array[Byte]]) = Iteratee.flatten(enumor &> enee |>> Iteratee.consume[String]()).run.asInstanceOf[Promise[String]]

    for {
      f <- useEnee(first);
      r <- useEnee(rest)
    } yield Ok("first : " + f + "n" + "rest" + r)
  }
}

def read2 = {
  def create = Enumerator.fromFile(Play.getFile("/conf/routes"))

  val file: Enumerator[Array[Byte]] = create
  val file2: Enumerator[Array[Byte]] = create

  (file &> Traversable.take[Array[Byte]](1),file2 &> Traversable.drop[Array[Byte]](1))

}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读