Gzip для чтения файлов Scala

Я новичок в скале и выясняю вещи на лету. У меня есть программа, которая должна читать файлы Gzip разных размеров - 20 КБ, 2 МБ и 150 МБ (Да, сжатый файл имеет размер 150 МБ). Я бы подумал не о том, чтобы по-разному читать разные файлы, а о стандартном сквозном. Большинство подходов, которые я вижу, используют размер буфера 64 МБ для чтения файлов построчно? Каков наилучший (читай как, *самая быстрая и чистая память * способ сделать это) способ сделать это?

Заранее спасибо за помощь!

обновление 1:

Большие улучшения в скорости чтения.(Я бы даже поделился своими очками кармы) Спасибо ТАК!:)

Но я заметил, что, поскольку каждый мой файл имеет около 10 тыс. Строк, при записи их в файл требуется много времени, чтобы преобразовать String Iterator в строку перед записью в файл. Я могу сделать два подхода,

  1. Итератор построчно и запись построчно в файл.
  2. Повторяйте строку за строкой, чтобы преобразовать строки в большую строку ("\n" с разделителями) и записать эту большую строку в файл.

Я предполагаю, что [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 ответ

Решение

Ваша проблема с памятью вызвана слишком большим количеством открытых файлов, а не размером файлов. Вам нужен механизм для автоматического закрытия каждого файла после прочтения.

Один из способов сделать это:

      // 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()
          }

Обратите внимание, что файлы закрываются, только если итерация завершена, то есть весь файл читается. Если (по какой-то причине) вы не прочитали весь файл, вам необходимо вручную закрыть файл.

Другие вопросы по тегам