69 Stimmen

Wie liest man eine Datei in eine Seq von Zeilen in F# ein?

Dies ist die C#-Version:

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

Aber eine direkte Übersetzung benötigt eine veränderbare Variable.

104voto

Joel Mueller Punkte 27700

Wenn Sie .NET 4.0 verwenden, können Sie einfach File.ReadLinesverwenden.

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

val readLines : string -> seq

1 Stimmen

Erfordert dies das Halten der gesamten Datei im Speicher auf einmal oder kann es Zeile für Zeile verarbeiten?

20 Stimmen

"Die Methoden ReadLines und ReadAllLines unterscheiden sich wie folgt: Wenn Sie ReadLines verwenden, können Sie mit dem Auflisten der Sammlung von Zeichenfolgen beginnen, bevor die gesamte Sammlung zurückgegeben wird; wenn Sie ReadAllLines verwenden, müssen Sie auf das gesamte Array von Zeichenfolgen warten, bevor Sie auf das Array zugreifen können. Daher kann ReadLines bei der Arbeit mit sehr großen Dateien effizienter sein."

77voto

ChaosPandion Punkte 75527
öffnen System.IO

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

0 Stimmen

Vielen Dank! Übrigens, gibt es eine Bibliotheksfunktion dafür?

0 Stimmen

@David - Es sollte auf jeden Fall so sein. Ich glaube, dass die .NET-Bibliotheken langsam mehr in Richtung IEnumerable-Schnittstellen migrieren.

1 Stimmen

Ich musste eine Datei lesen, die bereits von einem anderen Prozess geöffnet war, also habe ich es geändert zu: use fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); use sr = new StreamReader(fs)

21voto

Tomas Petricek Punkte 233658

Um die Frage zu beantworten, ob es eine Bibliotheksfunktion gibt, um dieses Muster zu kapseln - es gibt genau keine Funktion dafür, aber es gibt eine Funktion, die es Ihnen ermöglicht, eine Sequenz aus einem bestimmten Zustand zu generieren, namens Seq.unfold. Sie können sie verwenden, um die Funktionalität wie oben implementieren:

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

Der Wert sr repräsentiert den Stream-Reader und wird als Zustand übergeben. Solange er Ihnen nicht-Null-Werte liefert, können Sie Some zurückgeben, das ein Element zur Generierung und den Zustand (der sich ändern könnte, wenn Sie wollten) enthält. Wenn es null liest, entsorgen wir es und geben None zurück, um die Sequenz zu beenden. Dies ist keine direkte Entsprechung, da der StreamReader nicht ordnungsgemäß entsorgt wird, wenn eine Ausnahme ausgelöst wird.

In diesem Fall würde ich definitiv Sequenzausdruck verwenden (der in den meisten Fällen eleganter und lesbarer ist), aber es ist nützlich zu wissen, dass es auch mit einer Funktionsaufruf geschrieben werden könnte.

0 Stimmen

Beim Verwenden dessen erhalte ich die folgende Ausnahme: {"Ausnahme beim Lesen eines geschlossenen TextReader."} an der match sr.ReadLine() with Zeile. Kann mir bitte jemand helfen, warum?

0 Stimmen

@AruniRC Ich denke, die Lösung von @ ChaosPandion ist viel schöner als die Verwendung von unfold, daher würde ich das bevorzugen :-)

0 Stimmen

@AruniRC, die Sequenz ist träge - wenn Sie sie später im Code auswerten, könnte der Reader bereits geschlossen sein, daher der Kann nicht aus einem geschlossenen TextReader lesen. Sie müssen die Auswertung der Sequenz sofort erzwingen, zum Beispiel durch Konvertieren in eine Liste mit Seq.toList oder irgendeinem anderen Trick.

15voto

maria Punkte 366
    lassen Sie Zeilen = File.ReadLines(Pfad)                

    // Überprüfen
    Zeilen |> Seq.iter(fun x -> printfn  "%s" x)

5voto

Lars Tackmann Punkte 19195

Im .NET 2/3 können Sie Folgendes tun:

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

und im .NET 4:

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

1 Stimmen

Der erste von diesen ist nicht faul (ReadAllLines liest alle Zeilen eifrig in ein Array).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X