Take the 2-minute tour ×

I want to write a Scala script to recursively process all files in a directory. For each file I'd like to see if there are any cases where a string occurs at line X and line X - 2. If a case like that occurs I'd like to stop processing that file, and add that filename to a map of filenames to occurrence counts. I just started learning Scala today, I've got the file recurse code working, and need some help with the string searching, here's what I have so far:

import java.io.File
import scala.io.Source

val s1= "CmdNum = 506"
val s2 = "Data = [0000,]"

def processFile(f: File) {
  val lines = scala.io.Source.fromFile(f).getLines.toArray
  for (i = 0 to lines.length - 1) {
    // want to do string searches here, see if line contains s1 and line two lines above also contains s1

def recursiveListFiles(f: File): Array[File] = {
  val these = f.listFiles
  if (these != null) {
    for (i = 0 to these.length - 1) {
      if (these(i).isFile) {
    these ++ these.filter(_.isDirectory).flatMap(recursiveListFiles)
  else {

println(recursiveListFiles(new File(args(0))))
share|improve this question

3 Answers 3

up vote 6 down vote accepted

You can do something like this:

def processFile(f: File) {
  val src = Source.fromFile(f)
  val hit = src.getLines().sliding(3).exists{ 
    case List(l0, l1, l2) => l0.contains(s1) && l2.contains(s1)
    case _ => false
  // do something depending on hit like adding to a Map

First you don't need to convert to an array, you can preserve the iterator to only read the lines necessary to find a match.

You can use sliding to get a derived iterator using a sliding window of 3 lines where you look for the string on line i and i+2.

exists tests whether an element of this sliding iterator satisfy a predicate. The case will pattern match the 3 lines from the sliding window element into 3 vals for convenience. I had to use the REPL to find out what type the sliding was really returning.

Finally don't forget to close src.

If you need the occurrence count:

  val count = src.getLines().sliding(3).filter{ 
    case _ => false

You filter the occurrences and then get the size...

edited for match error on files shorter than 3 lines

share|improve this answer
Thanks for the response, I tried it out but an getting an exception when it's processing the files: –  fred basset Jan 7 '11 at 22:07
scala.MatchError: List(2010-05-31 17:31:06.015 UTC+0000 INFO [xxx-HostSy ncThread-Runnable->HostSync-176666318810351] estation.services.timesync.TimeSync - Successful time sync with host 'www04.xxx.com:80';: parsed resp onse of 1275327066705 into system time of Mon May 31 17:31:06 UTC 2010) at Main$$anon$1$$anonfun$1.apply(506.scala:13) at Main$$anon$1$$anonfun$1.apply(506.scala:13) at scala.collection.Iterator$class.exists(Iterator.scala:655) at scala.collection.Iterator$GroupedIterator.exists(Iterator.scala:772) –  fred basset Jan 7 '11 at 22:07
@fred, I added case _ => false to handle short files. –  huynhjl Jan 7 '11 at 22:26
Arguably, I'd think sliding 3 returning a list with less than 3 elements is a bug. –  Daniel C. Sobral Jan 7 '11 at 22:31
Thanks guys, nice job. This newfangled Scala sure is good at expressing what you want with very few LOC :-) –  fred basset Jan 8 '11 at 1:43

Here's an alternative way of doing this:

import java.io.File
import scala.io.Source

val s1= "CmdNum = 506"

def filesAt(f: File): Array[File] = if (f.isDirectory) f.listFiles flatMap filesAt else Array(f)

def filterFiles(arr: Array[File]) = arr filter (
    fromFile _
    getLines ()
    sliding 3
    exists { 
        case List(l1, l2, l3) => List(l1, l3) forall (_ contains s1)
        case _ => false

println(filterFiles(filesAt(new File(args(0)))))

Though I'll confess I cheated a bit. I actually had to write this instead of Source fromFile _:


Because, otherwise, Scala would barf on invalid UTF-8 encodings.

share|improve this answer

It needs refining to deal with files shorter than 3 lines, but at a first stab I'd try something like this:

def checkFile(file: File) = {
  val lines = ...
  (lines zip lines.tail.tail) exists { _1 = _2 }


val files = ...
val validFiles = files filter { checkFile }

Apologies for being so brief, I'm answering on my mobile...

share|improve this answer
Ah files having less than 3 lines, that explains the match error in my answer :) –  huynhjl Jan 7 '11 at 22:23

Your Answer


