2012-04-26 14 views
6

मैं एक साधारण फ़ाइल लिखना चाहता हूं जो टेक्स्ट फ़ाइल की पंक्तियों पर पुनरावृत्त हो। मैं 2.8 एक कर सकता है में विश्वास करते हैं:फ़ाइल की लाइनों पर इटरेटिंग

def lines(filename: String) : Iterator[String] = { 
    scala.io.Source.fromFile(filename).getLines 
} 

और कहा कि कि था, लेकिन 2.9 में ऊपर काम नहीं करता है और बदले में मुझे क्या करना चाहिए:

def lines(filename: String) : Iterator[String] = { 
    scala.io.Source.fromFile(new File(filename)).getLines() 
} 

अब, मुसीबत है, मैं चाहता हूँ एक for समझ में ऊपर iterators रचना के लिए:

for (l1 <- lines("file1.txt"); l2 <- lines("file2.txt")){ 
    do_stuff(l1, l2) 
} 

यह फिर से, 2.8 के साथ ठीक काम करता था, लेकिन एक "बहुत मा का कारण बनता है नई खुली फ़ाइलें " 2.9 में फेंकने के लिए अपवाद। यह समझा जा सकता है - दूसरी प्रत्येक पंक्ति के लिए फ़ाइल में दूसरी lines समझ में समाप्त होता है (और बंद नहीं होता)।

मेरे मामले में, मुझे पता है कि "file1.txt" बड़ा है और मैं
स्मृति में चूसना करने के लिए नहीं करना चाहते हैं, लेकिन दूसरी फ़ाइल छोटा है, तो मैं एक अलग linesEager इसलिए की तरह लिख सकते हैं:

def linesEager(filename: String): Iterator[String] = 
    val buf = scala.io.Source.fromFile(new File(filename)) 
    val zs = buf.getLines().toList.toIterator 
    buf.close() 
    zs 

और उसके बाद में मेरी के लिए-समझ कर दें:

for (l1 <- lines("file1.txt"); l2 <- linesEager("file2.txt")){ 
    do_stuff(l1, l2) 
} 

यह काम करता है, लेकिन स्पष्ट रूप से बदसूरत है। क्या कोई उपर्युक्त प्राप्त करने के लिए एक समान & स्वच्छ तरीका सुझा सकता है। ऐसा लगता है कि आपको इटरेटर lines से close फ़ाइल को अंत तक पहुंचने पर फ़ाइल की आवश्यकता है, और यह 2.8 में हो रहा है, यही कारण है कि यह वहां काम करता है?

धन्यवाद!

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") 
    } 

} 

2.9.0 पर मैं scalac WordsFail.scala साथ संकलन और उसके बाद मैं इस मिल:

[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) 
+3

कोड एक मेरे लिए आरईपीएल (स्कैला 2.9) में काम करता है। –

+0

दुर्भाग्यवश यह नहीं था; –

+0

@userunknown यह काम करता है लेकिन यह स्केल नहीं करता है। (बड़ी फ़ाइलों/कई लाइनों की कल्पना करो।) – Debilski

उत्तर

13

scala-arm स्वचालित रूप से संसाधनों को बंद करने के लिए एक महान तंत्र प्रदान करता है जब आप उनके साथ काम करते हैं।

import resource._ 
import scala.io.Source 

for (file1 <- managed(Source.fromFile("file1.txt")); 
    l1 <- file1.getLines(); 
    file2 <- managed(Source.fromFile("file2.txt")); 
    l2 <- file2.getLines()) { 
    do_stuff(l1, l2) 
} 

लेकिन जब तक आप जब तुम file1.txt के माध्यम से पाशन कर रहे हैं बदलने के लिए file2.txt की सामग्री पर भरोसा कर रहे हैं, यह है कि पढ़ने के लिए एक List आप पाश से पहले में सबसे अच्छा होगा। इसे Iterator में बदलने की आवश्यकता नहीं है।

+0

क्या यह पूरी सूची को स्मृति में रखने वाली सूची में परिवर्तित नहीं हो रहा है? मैं उस से बचने की उम्मीद कर रहा था ... –

+0

लेकिन 'file2.txt' छोटा है, इसलिए इसे स्वीकार्य होना चाहिए। इसके अलावा, यही है कि आपकी 'लाइनेंगर' ('.toList') करता है, सिवाय इसके कि आप इसे स्मृति में बना रहे हैं और इसे 'file1.txt' में प्रत्येक पंक्ति के लिए फेंक रहे हैं। – leedm777

+0

हाय डेव, हाँ आप सही हैं। मुझे इस बात की ग़लतफ़हमी थी कि समझ में आने वाले विभिन्न कार्यों में एक ही प्रकार का होना था, और इसलिए 'toList' पर्याप्त होने पर' 'toList.toIterator 'को अपनाना होगा ... धन्यवाद! –

2

शायद तुम करना चाहिए -

BTW यहाँ कि इस मुद्दे से पता चलता पूरा कार्यक्रम का एक न्यूनतम संस्करण है स्कैला-आर्म (https://github.com/jsuereth/scala-arm) पर एक नज़र डालें और फ़ाइलों को बंद करने दें (फ़ाइल इनपुट स्ट्रीम) पृष्ठभूमि में स्वचालित रूप से हो जाते हैं।