Chciałbym napisać prostą funkcję, która iteruje po liniach pliku tekstowego. Wierzę w 2.8
jeden mógłby zrobić:Iterowanie po liniach pliku
def lines(filename: String) : Iterator[String] = {
scala.io.Source.fromFile(filename).getLines
}
i tyle, ale w 2.9
powyższe nie działa, a zamiast tego muszę zrobić:
def lines(filename: String) : Iterator[String] = {
scala.io.Source.fromFile(new File(filename)).getLines()
}
Teraz problem jest, chcę komponować powyższe iteratory w for
zrozumieniem:
for (l1 <- lines("file1.txt"); l2 <- lines("file2.txt")){
do_stuff(l1, l2)
}
To znowu pracował w porządku z 2.8
ale powoduje „zbyt mA ny otwarte pliki " wyjątek, aby uzyskać wyrzucony w 2.9
. Jest to zrozumiałe - drugie zrozumienie kończy się otwarciem (i zamknięciem) pliku dla każdej linii w pierwszym.
W moim przypadku, ja wiem, że "file1.txt"
jest duży i nie chce ssać go do
pamięci, ale drugi plik jest niewielka, więc mogę napisać inny linesEager
jak tak:
def linesEager(filename: String): Iterator[String] =
val buf = scala.io.Source.fromFile(new File(filename))
val zs = buf.getLines().toList.toIterator
buf.close()
zs
a następnie skręcić w moją For-zrozumieniem na:
for (l1 <- lines("file1.txt"); l2 <- linesEager("file2.txt")){
do_stuff(l1, l2)
}
to działa, ale jest wyraźnie brzydkie. Czy ktoś może zaproponować jednolity sposób uzyskania powyższego celu? &. Wygląda na to, że potrzebujesz sposobu na iterator zwrócony przez lines
do close
pliku, gdy dojdzie do końca, i to musiało się dziać w 2.8
, dlaczego właśnie tam działało?
Dzięki!
BTW - tutaj jest minimalna wersja pełnego programu, który pokazuje problem:
import java.io.PrintWriter
import java.io.File
object Fail {
def lines(filename: String) : Iterator[String] = {
val f = new File(filename)
scala.io.Source.fromFile(f).getLines()
}
def main(args: Array[String]) = {
val smallFile = args(0)
val bigFile = args(1)
println("helloworld")
for (w1 <- lines(bigFile)
; w2 <- lines(smallFile)
)
{
if (w2 == w1){
val msg = "%s=%s\n".format(w1, w2)
println("found" + msg)
}
}
println("goodbye")
}
}
Na 2.9.0
skompilować z scalac WordsFail.scala
a następnie uzyskać to:
[email protected]:$ scalac WordsFail.scala
[email protected]:$ scala Fail passwd words
helloworld
java.io.FileNotFoundException: passwd (Too many open files)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:120)
at scala.io.Source$.fromFile(Source.scala:91)
at scala.io.Source$.fromFile(Source.scala:76)
at Fail$.lines(WordsFail.scala:8)
at Fail$$anonfun$main$1.apply(WordsFail.scala:18)
at Fail$$anonfun$main$1.apply(WordsFail.scala:17)
at scala.collection.Iterator$class.foreach(Iterator.scala:652)
at scala.io.BufferedSource$BufferedLineIterator.foreach(BufferedSource.scala:30)
at Fail$.main(WordsFail.scala:17)
at Fail.main(WordsFail.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at scala.tools.nsc.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:78)
at scala.tools.nsc.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:24)
at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:88)
at scala.tools.nsc.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:78)
at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:101)
at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:33)
at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:40)
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:56)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:80)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:89)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
Kod jeden działa dla mnie w REPL (Scala 2.9). –
To nie było ";" niestety. –
@userunknown Działa, ale nie skaluje. (Wyobraź sobie duże pliki/wiele linii.) – Debilski