Gzip文件阅读器Scala

时间:2013-11-05 17:32:26

标签: performance scala optimization file-io gzip

我是scala的新手并且在飞行中搞清楚事情。我有一个程序需要读取各种大小的Gzip文件 - 20KB,2MB和150MB(是的,压缩文件是150MB)。我认为不会有不同的方法来阅读不同的文件,而是标准的一个彻头彻尾的文件。我看到的大多数方法都使用64MB的缓冲区来逐行读取文件?什么是最好的(读作,* 最快和干净的内存* 这样做的方式)这样做的方法?

在此先感谢您的帮助!

更新1:

阅读率的大提升。(我甚至会分享我的业力点)谢谢! :)

但是,我注意到,由于我的每个文件都有大约10K行,而将它们写入文件,在写入文件之前将String Iterator转换为字符串需要很长时间。我可以做两种方法,< / p>

  1. 迭代器逐行逐行写入文件。
  2. 逐行迭代将行转换为大字符串(“\ n”分隔)并将该大字符串写入文件。
  3. 我假设[2]会更快。所以,这就是我正在做的写作,

    var processedLines = linesFromGzip(new File(fileName)).map(line => MyFunction(line))
    
    var  outFile = Resource.fromFile(outFileName)
    
    outFile.write(processedLines.mkString("\n"))  // severe overhead -> processedLines.mkString("\n")
    

    此外,我的分析(通过评论write()表明,写入并不需要花费太多时间,而是将processedLines转换为单个大字符串 - 它需要接近一秒 - 这是我的应用程序的成本很高。最好的方法是什么(再次清理没有任何内存泄漏)的方法。

1 个答案:

答案 0 :(得分:3)

您的内存问题是由于打开的文件太多而不是文件大小造成的。您需要一种机制,在阅读后自动关闭每个文件。

一种方法:

      // this Source closes at the end of iteration                        
      implicit def closingSource(source: Source) = new {
        val lines = source.getLines()
        var isOpen = true
        def closeAfterGetLines() = new Iterator[String] {
          def hasNext = isOpen && hasNextAndCloseIfDone
          def next() = {
            val line = lines.next()
            hasNextAndCloseIfDone
            line
          }
          private def hasNextAndCloseIfDone = if (lines.hasNext) true else { source.close() ; isOpen = false ; false }
        }
      }

然后你使用gzip阅读器:

def gzInputStream(gzipFile: File) = new GZIPInputStream(new BufferedInputStream(new FileInputStream(gzipFile)))

def linesFomGzip(gzipFile: File): Iterator[String] = {
            Source.fromInputStream(gzInputStream(gzipFile)).closeAfterGetLines()
          }

请注意,仅在迭代完成时才关闭文件,即读取整个文件。如果(由于某种原因)您没有读取整个文件,则需要手动关闭该文件。