简体   繁体   English

如何在 F# 中将文件读入一系列行

[英]How read a file into a seq of lines in F#

This is C# 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();
    }
  }
}

But directly translating needs a mutable variable.但是直接翻译需要一个可变变量。

If you're using .NET 4.0, you can just use File.ReadLines .如果您使用的是 .NET 4.0,则可以只使用File.ReadLines

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

val readLines : string -> seq<string>
open System.IO

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

To answer the question whether there is a library function for encapsulating this pattern - there isn't a function exactly for this, but there is a function that allows you to generate sequence from some state called Seq.unfold .要回答是否有用于封装此模式的库函数的问题 - 没有完全用于此的函数,但有一个函数允许您从称为Seq.unfold某个状态生成序列。 You can use it to implement the functionality above like this:您可以使用它来实现上述功能,如下所示:

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

The sr value represents the stream reader and is passed as the state. sr值表示流读取器并作为状态传递。 As long as it gives you non-null values, you can return Some containing an element to generate and the state (which could change if you wanted).只要它为您提供非空值,您就可以返回Some包含要生成的元素和状态(如果您愿意,可以更改)。 When it reads null , we dispose it and return None to end the sequence.当它读取null ,我们处理它并返回None以结束序列。 This isn't a direct equivalent, because it doesn't properly dispose StreamReader when an exception is thrown.这不是直接的等价物,因为它在抛出异常时没有正确处理StreamReader

In this case, I would definitely use sequence expression (which is more elegant and more readable in most of the cases), but it's useful to know that it could be also written using a higher-order function.在这种情况下,我肯定会使用序列表达式(在大多数情况下它更优雅且更具可读性),但知道它也可以使用高阶函数编写是很有用的。

    let lines = File.ReadLines(path)                

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

On .NET 2/3 you can do:在 .NET 2/3 上,您可以执行以下操作:

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

and on .NET 4:在 .NET 4 上:

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

In order to avoid the "System.ObjectDisposedException: Cannot read from a closed TextReader."为了避免“System.ObjectDisposedException:无法从关闭的 TextReader 读取”。 exception, use:例外,使用:

let lines = seq { yield! System.IO.File.ReadLines "/path/to/file.txt" }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM