2010-03-02 8 views
44

में लाइनों की एक seq में एक फ़ाइल को पढ़ने के इस सी # संस्करण है:कैसे एफ #

public static IEnumerable<string> ReadLinesEnumerable(string path) { 
    using (var reader = new StreamReader(path)) { 
    var line = reader.ReadLine(); 
    while (line != null) { 
     yield return line; 
     line = reader.ReadLine(); 
    } 
    } 
} 

लेकिन सीधे अनुवाद करने की जरूरत है एक परिवर्तनशील चर।

उत्तर

62
let readLines (filePath:string) = seq { 
    use sr = new StreamReader (filePath) 
    while not sr.EndOfStream do 
     yield sr.ReadLine() 
} 
+0

धन्यवाद! बीटीडब्ल्यू, क्या इसके लिए लाइब्रेरी फ़ंक्शन है? –

+0

@ डेविड - निश्चित रूप से होना चाहिए। मेरा मानना ​​है कि .NET पुस्तकालय धीरे-धीरे अधिक IENumerable इंटरफेस की तरफ बढ़ रहे हैं। – ChaosPandion

+1

मुझे किसी अन्य प्रक्रिया द्वारा पहले से खोला गया फ़ाइल पढ़ने की आवश्यकता है, इसलिए मैंने इस प्रकार संशोधित किया: 'fs = new fileStream (filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) का उपयोग करें; sr = new StreamReader (fs) ' – User

71

आप .NET 4.0 का उपयोग कर रहे हैं, तो आप सिर्फ File.ReadLines उपयोग कर सकते हैं।

> let readLines filePath = System.IO.File.ReadLines(filePath);; 

val readLines : string -> seq<string> 
+0

का उपयोग करें क्या इसे पूरी फ़ाइल को स्मृति में एक साथ रखने की आवश्यकता है, या क्या यह रेखा से लाइन को संसाधित कर सकता है? –

+12

"रीडलाइन और रीडअलाइनलाइन विधियां निम्नानुसार भिन्न होती हैं: जब आप रीडलाइन का उपयोग करते हैं, तो आप पूरे संग्रह को वापस करने से पहले तारों के संग्रह की गणना करना शुरू कर सकते हैं; जब आप रीडअलाइनलाइन का उपयोग करते हैं, तो आपको स्ट्रिंग्स की पूरी सरणी वापस आने से पहले लौटा दी जानी चाहिए सरणी का उपयोग करें। इसलिए, जब आप बहुत बड़ी फ़ाइलों के साथ काम कर रहे हैं, तो रीडलाइन अधिक कुशल हो सकती है। " –

17

सवाल इस पैटर्न encapsulating के लिए एक पुस्तकालय समारोह है कि क्या वहाँ उत्तर देने के लिए - वहाँ एक समारोह वास्तव में इस के लिए नहीं है, लेकिन वहाँ एक समारोह से कुछ राज्य Seq.unfold कहा जाता है आप अनुक्रम उत्पन्न करने के लिए अनुमति देता है । आप इस तरह से ऊपर कार्यक्षमता को लागू करने के लिए इसका इस्तेमाल कर सकते हैं:

new StreamReader(filePath) |> Seq.unfold (fun sr -> 
    match sr.ReadLine() with 
    | null -> sr.Dispose(); None 
    | str -> Some(str, sr)) 

sr मूल्य धारा पाठक का प्रतिनिधित्व करता है और राज्य के रूप में पारित कर दिया है। जब तक यह आपको गैर-शून्य मान देता है, तो आप Some को उत्पन्न करने के लिए तत्व बना सकते हैं और राज्य (जो आप चाहते थे तो बदल सकता है)। जब यह null पढ़ता है, तो हम इसका निपटान करते हैं और अनुक्रम को समाप्त करने के लिए None लौटाते हैं। यह प्रत्यक्ष समतुल्य नहीं है, क्योंकि जब कोई अपवाद फेंक दिया जाता है तो यह ठीक से StreamReader का निपटान नहीं करता है।

इस मामले में, मैं निश्चित रूप से अनुक्रम अभिव्यक्ति का उपयोग करता हूं (जो अधिकतर मामलों में अधिक सुरुचिपूर्ण और अधिक पठनीय है), लेकिन यह जानना उपयोगी है कि इसे उच्च-आदेश फ़ंक्शन का उपयोग करके भी लिखा जा सकता है।

+0

इसका उपयोग करने पर मुझे निम्नलिखित अपवाद मिल रहा है: 'मिलान के साथ 'मिलान sr.ReadLine() पर {" एक बंद टेक्स्ट रीडर से नहीं पढ़ा जा सकता। "}। कृपया कोई मदद क्यों करें? – AruniRC

+0

@ अरुनीआरसी मुझे लगता है कि @ChosPandion द्वारा समाधान 'unfold' का उपयोग कर एक से अधिक अच्छा है, इसलिए मैं इसके साथ जाऊंगा :-) –

+0

@ अरुनीआरसी, सेक आलसी है - जब तक आप इसे कोड में बाद में मूल्यांकन करते हैं , पाठक पहले ही बंद हो सकता है, इसलिए 'बंद टेक्स्ट रीडर से पढ़ा नहीं जा सकता'। आपको तुरंत अनुक्रम का मूल्यांकन करना होगा, उदाहरण के लिए 'Seq.toList', या किसी अन्य चाल के साथ सूची में परिवर्तित करके। –

3

नेट 2/3 पर आप कर सकते हैं:

let readLines filePath = File.ReadAllLines(filePath) |> Seq.cast<string> 

और .NET 4 पर:

let readLines filePath = File.ReadLines(filePath);; 
+0

इनमें से पहला आलसी नहीं है ('ReadAllLines 'उत्सुकता से सभी सरणी को सरणी में पढ़ता है)। –

8
let lines = File.ReadLines(path)     

    // To check 
    lines |> Seq.iter(fun x -> printfn "%s" x)