Better way to read a file line by line?

2,841 views
Skip to first unread message

Cecil Westerhof

unread,
Jan 29, 2013, 5:15:28 PM1/29/13
to scala...@googlegroups.com
In java I used:
br = new BufferedReader(new FileReader(filename));
while ((sCurrentLine = br.readLine()) != null) {

This does not work in scala. Because of this I now use:
br = new BufferedReader(new FileReader(filename))
while ({sCurrentLine = br.readLine(); sCurrentLine != null}) {

Is this a good way, or is there a better way?

--
Cecil Westerhof

Alec Zorab

unread,
Jan 29, 2013, 5:33:37 PM1/29/13
to Cecil Westerhof, scala-user
val source = io.Source.fromFile(k)
val linesIterator = source.getLines
//... do some stuff...
source.close()



--
Cecil Westerhof

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



Alec Zorab

unread,
Jan 29, 2013, 6:56:45 PM1/29/13
to Cecil Westerhof, scala-user
you'd have to show me your actual code and the input file, otherwise there's not much I can tell you other than "works for me"


On 29 January 2013 23:18, Cecil Westerhof <cldwes...@gmail.com> wrote:
2013/1/29 Alec Zorab <alec...@gmail.com>:

> val source = io.Source.fromFile(k)
> val linesIterator = source.getLines
> //... do some stuff...
> source.close()

Two strange things happen:
- Lines are read in parts instead of complete (but not always)
- At a certain moment the program crashes with:
java.nio.charset.MalformedInputException: Input length = 1
        at java.nio.charset.CoderResult.throwException(CoderResult.java:277)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:337)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:176)
        at java.io.InputStreamReader.read(InputStreamReader.java:184)
        at java.io.BufferedReader.fill(BufferedReader.java:153)
        at java.io.BufferedReader.readLine(BufferedReader.java:316)
        at java.io.BufferedReader.readLine(BufferedReader.java:379)
        at scala.io.BufferedSource$BufferedLineIterator.hasNext(BufferedSource.scala:67)
        at scala.collection.Iterator$class.foreach(Iterator.scala:772)
        at scala.io.BufferedSource$BufferedLineIterator.foreach(BufferedSource.scala:43)
        at HondenBelasting$.processFile(hondenbelasting.scala:201)

My code is:
            val source = io.Source.fromFile(filename)
            val linesIterator = source.getLines
            for (line <- linesIterator) {

--
Cecil Westerhof

Michael Schmitz

unread,
Jan 29, 2013, 7:05:14 PM1/29/13
to Alec Zorab, Cecil Westerhof, scala-user
I'm guessing you have a file with an unexpected character encoding.
Specify UTF8 (or the correct encoding for your file).

val source = io.Source.fromFile(k, "UTF8")

Peace. Michael

Alec Zorab

unread,
Jan 30, 2013, 2:37:04 AM1/30/13
to scala-user

Forwarding to list.

---------- Forwarded message ----------
From: "Cecil Westerhof" <cldwes...@gmail.com>
Date: 30 Jan 2013 04:21
Subject: Re: [scala-user] Better way to read a file line by line?
To: "Alec Zorab" <alec...@gmail.com>
Cc:

2013/1/30 Cecil Westerhof <cldwes...@gmail.com>:
> It has to do with character encoding as Michael thought.
>
> 2013/1/30 Alec Zorab <alec...@gmail.com>:

>> you'd have to show me your actual code and the input file, otherwise there's
>> not much I can tell you other than "works for me"
>
> The following goes wrong with the supplied file.
>
> import scala.io.Source
>
>
> object Test {
>     def main(args: Array[String]) = {
>         processFile("test")
>     }
>
>     def processFile(filename : String) {
>         for (line <- Source.fromFile(filename, "UTF8").getLines()) {
>           println(line)
>         }
>     }
>
> }
>
> When I change "UTF8" into "UTF16", the test file is processed
> correctly, but other files are not processed correctly. So I am afraid
> that I have to return to my original solution.

The following seems to work:
            for (line <- Source.fromFile(filename, "ISO-8859-5").getLines) {

--
Cecil Westerhof

Cecil Westerhof

unread,
Jan 30, 2013, 3:50:37 AM1/30/13
to scala...@googlegroups.com
Was send to Alec instead of the list. My bad.

2013/1/30 Cecil Westerhof <cldwes...@gmail.com>:
> 2013/1/30 Cecil Westerhof <cldwes...@gmail.com>:
>> 2013/1/30 Cecil Westerhof <cldwes...@gmail.com>:
>>> It has to do with character encoding as Michael thought.
>>>
>>> 2013/1/30 Alec Zorab <alec...@gmail.com>:
>>>> you'd have to show me your actual code and the input file, otherwise there's
>>>> not much I can tell you other than "works for me"
>>>
>>> The following goes wrong with the supplied file.
>>>
>>> import scala.io.Source
>>>
>>>
>>> object Test {
>>> def main(args: Array[String]) = {
>>> processFile("test")
>>> }
>>>
>>> def processFile(filename : String) {
>>> for (line <- Source.fromFile(filename, "UTF8").getLines()) {
>>> println(line)
>>> }
>>> }
>>>
>>> }
>>>
>>> When I change "UTF8" into "UTF16", the test file is processed
>>> correctly, but other files are not processed correctly. So I am afraid
>>> that I have to return to my original solution.
>>
>> The following seems to work:
>> for (line <- Source.fromFile(filename, "ISO-8859-5").getLines) {
>
> BTW: is it a bug that I need to use an encoding with this solution and not with:
> br = new BufferedReader(new FileReader(filename))
> while ({sCurrentLine = br.readLine(); sCurrentLine != null}) {
>
> With the solution I now use I do not close the source. Is that a bug
> and should I use something like:
> val source = Source.fromFile(filename, "ISO-8859-5")
> for (line <- source.getLines) {
> .
> .
> .
> source.close()
> or is the solution correct?
>
> --
> Cecil Westerhof



--
Cecil Westerhof
Message has been deleted

Rahat Hossain

unread,
Jul 24, 2013, 3:13:44 AM7/24/13
to scala...@googlegroups.com, Cecil Westerhof
Cool!
Initially didn't work
Looks even working from REPL

scala> import scala.io.Source
import scala.io.Source

scala> for(lines <- Source.fromFile("test1.txt").getLines){
     | println(lines)
     | }
Hello

Test

scala>

Alec Zorab

unread,
Jul 24, 2013, 3:31:04 AM7/24/13
to Rahat Hossain, scala-user, Cecil Westerhof
Just as a note - you know the version of scala you're running is almost pre-historic, right?

vatel

unread,
Jul 24, 2013, 4:16:48 AM7/24/13
to scala...@googlegroups.com
Rahat,

maybe this thread is useful for you:
https://groups.google.com/forum/#!topic/scala-user/7Unm61KW_GQ

--
Victor

On 24.07.2013 11:00, Rahat Hossain wrote:
> is Source.fromFile still a valid function to use ?
> I can't see fromFile function in the follwoing URL
> http://www.scala-lang.org/api/current/index.html#scala.io.Source


Som Snytt

unread,
Jul 24, 2013, 6:13:00 AM7/24/13
to Rahat Hossain, scala-user

> Welcome to Scala version 2.7.7.final

You want to upgrade to the version indicated here and use Source.fromPath:

http://stackoverflow.com/a/17643854




On Wed, Jul 24, 2013 at 12:00 AM, Rahat Hossain <rahat....@gmail.com> wrote:
is Source.fromFile still a valid function to use ?
I can't see fromFile function in the follwoing URL

moreover getting following error while trying:

Welcome to Scala version 2.7.7.final (Java HotSpot(TM) Client VM, Java 1.6.0_22)
.
Type in expressions to have them evaluated.
Type :help for more information.

scala> for(lines <- Source.fromFile("test.txt", "UTF8").getLines()){
     | println(line)
     | }
<console>:5: error: not found: value Source
       for(lines <- Source.fromFile("test.txt", "UTF8").getLines()){
                    ^

scala>


On Wednesday, January 30, 2013 9:33:37 AM UTC+11, AlecZorab wrote:

Alec Zorab

unread,
Jul 24, 2013, 6:35:44 AM7/24/13
to Som Snytt, Rahat Hossain, scala-user
On 24 July 2013 11:13, Som Snytt <som....@gmail.com> wrote:

> Welcome to Scala version 2.7.7.final

You want to upgrade to the version indicated here and use Source.fromPath:

http://stackoverflow.com/a/17643854


Wait. What? Don't give people totally insane advice on the mailing lists, they might take you seriously.

io.Source.fromFile is fine, but I would strongly recommend updating to scala 2.10.2, which is the most recently released version. 

Rahat Hossain

unread,
Jul 25, 2013, 6:33:17 PM7/25/13
to scala...@googlegroups.com, Rahat Hossain
Version wasn't issue here.  
However, I was also missing import  on the REPL 
such as following works

scala> import scala.io._
import scala.io._

scala> for(l <- Source.fromFile("test.txt").getLines){println(l)}

Michael Shields

unread,
Jul 25, 2013, 7:01:49 PM7/25/13
to scala...@googlegroups.com

I’m reading Odersky, et al. Programming in Scala, Second Edition, and in section 7.4 (page 124) he gives the example:

def scalaFiles = 

    for {

      file <- filesHere

      if file.getName.endsWith(".scala")

    } yield file

 

 

He states that the syntax of a for-yield expression is:

                for clauses yield body

Where the yield “goes before the entire body.”

 

I have two questions. First, it seems like here the “generator” or what he calls “clauses” for the for loop is in the braces rather than in the “normal” parens. Second, it seems there is no “body” in this example.

 

He then gives a second example:

 

val forLineLengths =

    for {

      file <- filesHere

      if file.getName.endsWith(".scala")

      line <- fileLines(file)

      trimmed = line.trim

      if trimmed.matches(".*for.*") 

    } yield trimmed.length

 

Again, the nested iteration “generator” in the braces and there is no body.

 

Can one have a syntax like:

for (generator) yield x { body where we do some work and calculate x}

 

Thanks,

Mike Shields

eduardo.m.cavalcanti

unread,
Jul 25, 2013, 7:30:41 PM7/25/13
to Michael Shields, scala...@googlegroups.com
1- If you use parens, separate the expressions with commas, i.e.
for (file; if file.getName.endsWith(".scala"); ... ; ...)
 
2- For the yield block, follow same rule as if block in java: just one expression, no need for braces. yielded value is the last expression.
 
3 - You did not asked but: the yielded result type is the same as the type of the expression to the right of the <- sign in the for beginning.
 
Someone please correct if I am wrong or unprecise.
 
 

Em 25/07/2013 20:01, Michael Shields < mshi...@vigilantsys.com > escreveu:

I’m reading Odersky, et al. Programming in Scala, Second Edition, and in section 7.4 (page 124) he gives the example:

 

def scalaFiles = 

    for {

      file

      if file.getName.endsWith(".scala")

    } yield file

 

 

He states that the syntax of a for-yield expression is:

                for clauses yield body

Where the yield “goes before the entire body.”

 

I have two questions. First, it seems like here the “generator” or what he calls “clauses” for the for loop is in the braces rather than in the “normal” parens. Second, it seems there is no “body” in this example.

 

He then gives a second example:

 

val forLineLengths =

    for {

      file

      if file.getName.endsWith(".scala")

      line

      trimmed = line.trim

      if trimmed.matches(".*for.*") 

    } yield trimmed.length

 

Again, the nested iteration “generator” in the braces and there is no body.

 

Can one have a syntax like:

for (generator) yield x { body where we do some work and calculate x}

 

Thanks,

Mike Shields

 

--

Alec Zorab

unread,
Jul 25, 2013, 8:09:27 PM7/25/13
to Rahat Hossain, scala-user
yeah, you'll notice that in the original code I posted in January, I invoke it as io.Source.fromFile

Michael Shields

unread,
Jul 25, 2013, 10:27:21 PM7/25/13
to eduardo.m.cavalcanti, scala...@googlegroups.com

Eduardo,

 

For #1, I think you can use parens and use separate lines without commas:

val strList = List("one", "to", "two", "three", "five", "seven")

for (str <- strList

      if str.endsWith("e")

    ) yield str.length

 

Seems to work. So I’m still not sure when to use () and when to use {}.

 

For #2, I’m coming to Scala from C/C++, python, perl, etc., but not java so I’m not sure what a block is java is, but if I understand you, I can put a single expression or a block in {} with the yielded value the last expression.

 

I’m sure your third point is not correct:

scala> for (i<-1 to 10) yield i + 0.1f

res0: scala.collection.immutable.IndexedSeq[Float] = Vector(1.1, 2.1, 3.1, 4.1,5.1, 6.1, 7.1, 8.1, 9.1, 10.1)

 

What I really want to figure out how to do is something like:

val strList = List("one", "to", "two", "three", "five", "seven")

for (str <- strList

      if str.endsWith("e")

    ) yield x { val x = str.length -1}

 

But this gives and error as “x” is undefined for the yield, and I want to do calculations to figure out what to yield in each loop. I know how to do this is C in an imperative style: Define a collection before the loop and fill in with the loop, one member at a time. I’m trying to understand the Scala way to do the same thing in a functional style.  I can’t figure out how to use yield with the body of the for loop where the calculations may be not trivial.

 

Every example with yield that I have seen has nothing being done in the body (after the yield expression).

 

Thanks,

Mike

Seth Tisue

unread,
Jul 25, 2013, 10:43:53 PM7/25/13
to scala-user
On Thu, Jul 25, 2013 at 10:27 PM, Michael Shields
<mshi...@vigilantsys.com> wrote:
> What I really want to figure out how to do is something like:
> val strList = List("one", "to", "two", "three", "five", "seven")
> for (str <- strList
> if str.endsWith("e")
> ) yield x { val x = str.length -1}

This example is doable with just:

for (str <- strList if str.endsWith("e"))
yield str.length - 1

But note that if you want to do something complex after `yield`, you can, e.g.

for (str <- strList)
yield {
val a = str.length
val b = a * a
s"$b$b$b"
}

res2: List[String] = List(999, 444, 999, 252525, 161616, 252525)

eduardo.m.cavalcanti

unread,
Jul 25, 2013, 11:10:10 PM7/25/13
to Michael Shields, scala...@googlegroups.com
About the for() versus for{}, the result I get here is that you need semicolons beetween expressions when using ().

About the yield block you can do
 
yield expression
or
yield {
 expression 1
 ...
 expression n
 }
the yielded value is the last expression result
 
same for if
 
if (cond)
 expression
or
if (cond) {
  expression 1
  ...
  expression n
  }
 
 

Em 25/07/2013 23:27, Michael Shields < mshi...@vigilantsys.com > escreveu:

Eduardo,

 

For #1, I think you can use parens and use separate lines without commas:

val strList = List("one", "to", "two", "three", "five", "seven")

for (str

      if str.endsWith("e")

    ) yield str.length

 

Seems to work. So I’m still not sure when to use () and when to use {}.

 

For #2, I’m coming to Scala from C/C++, python, perl, etc., but not java so I’m not sure what a block is java is, but if I understand you, I can put a single expression or a block in {} with the yielded value the last expression.

 

I’m sure your third point is not correct:

scala> for (i

res0: scala.collection.immutable.IndexedSeq[Float] = Vector(1.1, 2.1, 3.1, 4.1,5.1, 6.1, 7.1, 8.1, 9.1, 10.1)

 

What I really want to figure out how to do is something like:

val strList = List("one", "to", "two", "three", "five", "seven")

for (str

      if str.endsWith("e")

    ) yield x { val x = str.length -1}

 

But this gives and error as “x” is undefined for the yield, and I want to do calculations to figure out what to yield in each loop. I know how to do this is C in an imperative style: Define a collection before the loop and fill in with the loop, one member at a time. I’m trying to understand the Scala way to do the same thing in a functional style.  I can’t figure out how to use yield with the body of the for loop where the calculations may be not trivial.

 

Every example with yield that I have seen has nothing being done in the body (after the yield expression).

 

Thanks,

Mike

 

From: eduardo.m.cavalcanti [mailto:eduardo.m....@uol.com.br]
Sent: Thursday, July 25, 2013 7:31 PM
To: Michael Shields
Cc: scala...@googlegroups.com
Subject: Re: [scala-user] Newbie question about for..yield

 

1- If you use parens, separate the expressions with commas, i.e.
for (file; if file.getName.endsWith(".scala"); ... ; ...)

 

2- For the yield block, follow same rule as if block in java: just one expression, no need for braces. yielded value is the last expression.

 

3 - You did not asked but: the yielded result type is the same as the type of the expression to the right of the

 

Someone please correct if I am wrong or unprecise.

eduardo.m.cavalcanti

unread,
Jul 25, 2013, 11:17:22 PM7/25/13
to eduardo.m.cavalcanti, scala...@googlegroups.com, mshi...@vigilantsys.com
This is absolutely correct:
 
val strList = List("one", "to", "two", "three", "five", "seven")
val result = for (str <- strList

     if str.endsWith("e")
        ) yield str.length

Regards
 
 

eduardo.m.cavalcanti

unread,
Jul 25, 2013, 11:32:15 PM7/25/13
to Michael Shields, scala...@googlegroups.com
About the 3rd point:

if you do
 
val strList = List("one", "to", "two", "three", "five", "seven")
val result = for (str <- strList; if str.endsWith("e")
        ) yield str.length
 
result will be a List
 
but if you do
 
val strList = Vector("one", "to", "two", "three", "five", "seven")
val result = for (str <- strList; if str.endsWith("e")
        ) yield str.length
 
result will be a Vector
 
and so on.
 
 
 

Em 25/07/2013 23:27, Michael Shields < mshi...@vigilantsys.com > escreveu:

Eduardo,

 

For #1, I think you can use parens and use separate lines without commas:

val strList = List("one", "to", "two", "three", "five", "seven")

for (str

      if str.endsWith("e")

    ) yield str.length

 

Seems to work. So I’m still not sure when to use () and when to use {}.

 

For #2, I’m coming to Scala from C/C++, python, perl, etc., but not java so I’m not sure what a block is java is, but if I understand you, I can put a single expression or a block in {} with the yielded value the last expression.

 

I’m sure your third point is not correct:

scala> for (i

res0: scala.collection.immutable.IndexedSeq[Float] = Vector(1.1, 2.1, 3.1, 4.1,5.1, 6.1, 7.1, 8.1, 9.1, 10.1)

 

What I really want to figure out how to do is something like:

val strList = List("one", "to", "two", "three", "five", "seven")

for (str

      if str.endsWith("e")

    ) yield x { val x = str.length -1}

 

But this gives and error as “x” is undefined for the yield, and I want to do calculations to figure out what to yield in each loop. I know how to do this is C in an imperative style: Define a collection before the loop and fill in with the loop, one member at a time. I’m trying to understand the Scala way to do the same thing in a functional style.  I can’t figure out how to use yield with the body of the for loop where the calculations may be not trivial.

 

Every example with yield that I have seen has nothing being done in the body (after the yield expression).

 

Thanks,

Mike

 

From: eduardo.m.cavalcanti [mailto:eduardo.m....@uol.com.br]
Sent: Thursday, July 25, 2013 7:31 PM
To: Michael Shields
Cc: scala...@googlegroups.com
Subject: Re: [scala-user] Newbie question about for..yield

 

1- If you use parens, separate the expressions with commas, i.e.
for (file; if file.getName.endsWith(".scala"); ... ; ...)

 

2- For the yield block, follow same rule as if block in java: just one expression, no need for braces. yielded value is the last expression.

 

3 - You did not asked but: the yielded result type is the same as the type of the expression to the right of the

 

Someone please correct if I am wrong or unprecise.

Tim Pigden

unread,
Jul 26, 2013, 1:16:17 AM7/26/13
to Michael Shields, scala-user
Firstly - a for comprehension is not a for loop like you're used to. So you're expecting the wrong thing.

You're thinking about it the wrong way round.

You could equally say "body" is what comes after the yield.
In both instances above the body consists of a single expression, but in my code body commonly consists of quite a lot of code and sits between {}
yield {
intermediate expressions
...
the last expression
}

So first example:

def scalaFiles = 

    for { // these are for clauses.  

      file <- filesHere

      if file.getName.endsWith(".scala")

    } yield {

       file // this is the body

  } 

or 
for ( file <- filesHere; if file.getName.endsWith(".scala") )
yield {
   file
}
should also work. But as the for clauses get more complex, the version as originally stated is probably to be preferred for clarity.

As Eduardo says - you can use () but then you have to separate the multiple clauses with semi-colons. There is a subtle distinction between what can go in the () and {} , which I'm not competent to explain and it isn't just here that you see it.


--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Tim Pigden
Optrak Distribution Software Limited
+44 (0)1992 517100
http://www.linkedin.com/in/timpigden
http://optrak.com
Optrak Distribution Software Ltd is a limited company registered in England and Wales.
Company Registration No. 2327613 Registered Offices: Orland House, Mead Lane, Hertford, SG13 7AT England 
This email and any attachments to it may be confidential and are intended solely for the use of the individual to whom it is addressed. Any views or opinions expressed are solely those of the author and do not necessarily represent those of Optrak Distribution Software Ltd. If you are not the intended recipient of this email, you must neither take any action based upon its contents, nor copy or show it to anyone. Please contact the sender if you believe you have received this email in error.

Stefan Wagner

unread,
Jul 26, 2013, 7:35:10 AM7/26/13
to scala...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 26.07.2013 04:27, Michael Shields wrote:
> What I really want to figure out how to do is something like:
>
> val strList = List("one", "to", "two", "three", "five", "seven")
> for (str <- strList if str.endsWith("e") ) yield x { val x =
> str.length -1}
>

Why do you want to use x before declaration, and if you use a block
after yield, why do you pull the x out of it?

val strList = List("one", "to", "two", "three", "five", "seven")
for (str <- strList
if str.endsWith("e")
) yield {
val x = str.length -1
x
}

But this simple code works without braces too:

for (str <- List("one", "to", "two", "three", "five", "seven")
if str.endsWith("e")
) yield { str.length -1 }

No need for an intermediate x, and no need for braces therefore, but
on the other side, they aren't prohibited. Could be interesting for
debugging.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with undefined - http://www.enigmail.net/

iEYEARECAAYFAlHyXu4ACgkQQeATqGpDnRoM0gCeOQlIuV/YFWFIq2fT0YEk2v7q
JLkAn2j7cnl+VUmc8X0SjvNSNaJgufh/
=g/L/
-----END PGP SIGNATURE-----
Reply all
Reply to author
Forward
0 new messages