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

当使用ZipInputStreams和ZipOutpuStreams时,如何避免Scala中的可

发布时间:2020-12-16 09:33:56 所属栏目:安全 来源:网络整理
导读:我试图读取一个zip文件,检查它是否有一些必需的文件,然后将所有有效的文件写入另一个zip文件。 basic introduction to java.util.zip有很多Java主题,我很想让我的代码更加Scala-native。具体来说,我想避免使用vars。这是我有的: val fos = new FileOutp
我试图读取一个zip文件,检查它是否有一些必需的文件,然后将所有有效的文件写入另一个zip文件。 basic introduction to java.util.zip有很多Java主题,我很想让我的代码更加Scala-native。具体来说,我想避免使用vars。这是我有的:

val fos = new FileOutputStream("new.zip");
val zipOut = new ZipOutputStream(new BufferedOutputStream(fos));

while (zipIn.available == 1) {
  val entry = zipIn.getNextEntry
  if (entryIsValid(entry)) {
    zipOut.putNewEntry(new ZipEntry("subdir/" + entry.getName())
    // read data into the data Array
    var data = Array[Byte](1024)
    var count = zipIn.read(data,1024)
    while (count != -1) {
      zipOut.write(data,count)
      count = zipIn.read(data,1024)
    }
  }
  zipIn.close
}
zipOut.close

我应该补充说,我正在使用Scala 2.7.7。

解决方法

我不认为使用被设计为以设计的方式以强制性方式工作的Java类有什么特别的错误。惯用的Scala包括能够使用惯用的Java,即使风格有冲突。

但是,如果你想要 – 也许是一个练习,或者也许是因为它稍微澄清逻辑 – 以更有功能的无变量方式来做到这一点,你可以这么做。在2.8中,这是非常好的,所以即使你使用2.7.7,我会给一个2.8的答案。

首先,我们需要设置问题,而不是完全没有,但假设我们有这样的事情:

import java.io._
import java.util.zip._
import scala.collection.immutable.Stream

val fos = new FileOutputStream("new.zip")
val zipOut = new ZipOutputStream(new BufferedOutputStream(fos))
val zipIn = new ZipInputStream(new FileInputStream("old.zip"))
def entryIsValid(ze: ZipEntry) = !ze.isDirectory

现在,鉴于此,我们要复制zip文件。我们可以使用的技巧是在collection.immutable.Stream中不断的方法。它所做的是为您执行一个延迟评估的循环。然后,您可以对结果进行过滤并终止并处理所需的结果。当你有一些想要成为迭代器的东西时,它是一种方便的模式,但不是。 (如果项目更新本身,可以在Iterable或Iterator中使用.iterate,这通常更好)。这里是这种情况下的应用程序,使用两次:一次获取条目,一次读取/写入数据块:

val buffer = new Array[Byte](1024)
Stream.continually(zipIn.getNextEntry).
  takeWhile(_ != null).filter(entryIsValid).
  foreach(entry => {
    zipOut.putNextEntry(new ZipEntry("subdir/"+entry.getName))
    Stream.continually(zipIn.read(buffer)).takeWhile(_ != -1).
      foreach(count => zipOut.write(buffer,count))
  })
}
zipIn.close
zipOut.close

密切关注。在一些线的尽头!我通常会在一行中写下这个,但是它更好的包装,所以你可以看到这一切。

为了防止这种情况不清楚,我们来解释一个不断的用途。

Stream.continually(zipIn.read(buffer))

这要求根据需要继续调用zipIn.read(缓冲区)多次,存储结果的整数。

.takeWhile(_ != -1)

这指定需要多少次,返回一个无限长的流,但是当它达到-1时将退出。

.foreach(count => zipOut.write(buffer,count))

这将处理流,依次使用每个项目(计数),并使用它来编写缓冲区。这样做的工作方式有点笨拙,因为你依靠zipIn刚刚被称为获取流的下一个元素 – 如果你再次尝试这样做,而不是单次通过流,那将会失败因为缓冲区将被覆盖。但这里没关系

所以,它是:稍微更紧凑,可能更容易理解,可能不太容易理解的方法更具功能(尽管仍然存在副作用)。在2.7.7中,相比之下,我实际上会使用Java的方式,因为Stream.continually不可用,并且构建自定义迭代器的开销对于这种情况是不值得的。 (这将是值得的,如果我要做更多的zip文件处理,然后可以重用代码。)

编辑:查找可用到零的方法是检测zip文件的结尾的一种薄片。我认为“正确”的方法是等待,直到你从getNextEntry返回null。考虑到这一点,我已经编辑了以前的代码(现在有一个takeWhile(_ => zipIn.available == 1),现在是一个takeWhile(_!= null)),并提供了一个基于2.7.7迭代器的版本下面(注意主循环有多小,一旦你完成了定义迭代器的工作,这确实使用了vars):

val buffer = new Array[Byte](1024)
class ZipIter(zis: ZipInputStream) extends Iterator[ZipEntry] {
  private var entry:ZipEntry = zis.getNextEntry
  private var cached = true
  private def cache { if (entry != null && !cached) {
    cached = true; entry = zis.getNextEntry
  }}
  def hasNext = { cache; entry != null }
  def next = {
    if (!cached) cache
    cached = false
    entry
  }
}
class DataIter(is: InputStream,ab: Array[Byte]) extends Iterator[(Int,Array[Byte])] {
  private var count = 0
  private var waiting = false
  def hasNext = { 
    if (!waiting && count != -1) { count = is.read(ab); waiting=true }
    count != -1
  }
  def next = { waiting=false; (count,ab) }
}
(new ZipIter(zipIn)).filter(entryIsValid).foreach(entry => {
  zipOut.putNextEntry(new ZipEntry("subdir/"+entry.getName))
  (new DataIter(zipIn,buffer)).foreach(cb => zipOut.write(cb._2,cb._1))
})
zipIn.close
zipOut.close

(编辑:李大同)

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

    推荐文章
      热点阅读