65 votes

Comment lire un fichier en une série de lignes en F# ?

Il s'agit de la version C# :

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();
    }
  }
}

Mais la traduction directe nécessite une variable mutable.

102voto

Joel Mueller Points 14985

Si vous utilisez .NET 4.0, vous pouvez simplement utiliser Fichier.LireLignes .

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

val readLines : string -> seq<string>

1 votes

Est-ce que cela nécessite de garder tout le fichier en mémoire en même temps, ou est-ce que cela peut être traité ligne par ligne ?

19 votes

" Les méthodes ReadLines et ReadAllLines diffèrent comme suit : Lorsque vous utilisez ReadLines, vous pouvez commencer à énumérer la collection de chaînes de caractères avant que la collection entière ne soit retournée ; lorsque vous utilisez ReadAllLines, vous devez attendre que le tableau entier de chaînes de caractères soit retourné avant de pouvoir accéder au tableau. Par conséquent, lorsque vous travaillez avec des fichiers très volumineux, ReadLines peut être plus efficace."

74voto

ChaosPandion Points 37025
open System.IO

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

0 votes

Merci ! Par ailleurs, existe-t-il une fonction de bibliothèque pour cela ?

0 votes

@David - Il devrait certainement y en avoir. Je crois que les bibliothèques .NET se dirigent lentement vers des interfaces plus IEnumerable.

1 votes

J'avais besoin de lire un fichier déjà ouvert par un autre processus, j'ai donc modifié comme : use fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); use sr = new StreamReader(fs)

21voto

Tomas Petricek Points 118959

Pour répondre à la question de savoir s'il existe une fonction de bibliothèque pour encapsuler ce modèle - il n'y a pas de fonction exactement pour cela, mais il existe une fonction qui vous permet de générer une séquence à partir d'un état appelé Seq.unfold . Vous pouvez l'utiliser pour mettre en œuvre la fonctionnalité ci-dessus comme ceci :

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

El sr représente le lecteur de flux et est passée comme état. Tant qu'il vous donne des valeurs non nulles, vous pouvez retourner Some contenant un élément à générer et l'état (qui peut changer si vous le souhaitez). Lorsqu'il lit null nous le jetons et le rendons None pour terminer la séquence. Ce n'est pas un équivalent direct, parce qu'il ne dispose pas correctement de StreamReader lorsqu'une exception est levée.

Dans ce cas, j'utiliserais sans aucun doute l'expression de séquence (qui est plus élégante et plus lisible dans la plupart des cas), mais il est utile de savoir qu'elle peut également être écrite à l'aide d'une fonction d'ordre supérieur.

0 votes

En l'utilisant, j'obtiens l'exception suivante : {"Impossible de lire à partir d'un TextReader fermé."} au niveau de l'écran d'accueil. match sr.ReadLine() with Vous pouvez m'aider à comprendre pourquoi ?

0 votes

@AruniRC Je pense que la solution de @ChaosPandion est bien plus belle que celle utilisant unfold Je suis donc d'accord avec cela :-)

0 votes

@AruniRC, le Seq est paresseux - au moment où vous l'évaluez plus tard dans le code, le lecteur peut déjà être fermé, d'où l'utilisation de l'option Cannot read from a closed TextReader . Vous devrez forcer l'évaluation de la séquence immédiatement, par exemple en la convertissant en liste avec Seq.toList ou une autre astuce.

5voto

Lars Tackmann Points 7448

Sur .NET 2/3, vous pouvez le faire :

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

et sur .NET 4 :

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

1 votes

Le premier d'entre eux n'est pas paresseux ( ReadAllLines lit avidement toutes les lignes dans un tableau).

4voto

Andrey Points 36869

Vérifiez cette méthode : File.ReadAllLines

ou vous voulez le traiter ligne par ligne ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X