2010-03-02 21 views
44

Esta es la versión C#:Cómo leer un archivo en una de las líneas siguientes en Fa #

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

pero necesita traducir directamente una variables mutables.

Respuesta

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

Gracias! Por cierto, ¿hay una función de biblioteca para eso? –

+0

@David - Sin duda debería haberlo. Creo que las bibliotecas .NET se están moviendo lentamente hacia más interfaces IEnumerable. – ChaosPandion

+1

Necesitaba leer un archivo ya abierto por otro proceso, así que lo modifiqué como: 'use fs = new FileStream (filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); use sr = new StreamReader (fs) ' – User

71

Si está utilizando .NET 4.0, sólo puede utilizar File.ReadLines.

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

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

¿Eso requiere mantener todo el archivo en la memoria a la vez, o puede procesar línea por línea? –

+12

"Los métodos ReadLines y ReadAllLines difieren de la siguiente manera: Cuando usa ReadLines, puede comenzar a enumerar la colección de cadenas antes de que se devuelva toda la colección; cuando usa ReadAllLines, debe esperar a que se devuelva toda la matriz de cadenas antes de que pueda acceda a la matriz. Por lo tanto, cuando trabaje con archivos muy grandes, ReadLines puede ser más eficiente ". –

17

Para responder a la cuestión de si existe una función de biblioteca para encapsular este patrón - no es una función exactamente para esto, pero no es una función que le permite generar secuencias de algún estado llamado Seq.unfold . Se puede utilizar para implementar la funcionalidad por encima de la siguiente manera:

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

El valor sr representa el lector corriente y se pasa como el estado. Siempre que le proporcione valores no nulos, puede devolver Some que contenga un elemento para generar y el estado (que podría cambiar si lo desea). Cuando dice null, lo desechamos y devolvemos None para finalizar la secuencia. Esto no es un equivalente directo, porque no dispone de forma adecuada StreamReader cuando se produce una excepción.

En este caso, definitivamente utilizaría la expresión de secuencia (que es más elegante y más legible en la mayoría de los casos), pero es útil saber que también podría escribirse utilizando una función de orden superior.

+0

sobre el uso de esto obtengo la siguiente excepción: {"No se puede leer desde un TextReader cerrado."} En la línea 'match sr.ReadLine() with'. cualquier ayuda, por favor, ¿por qué? – AruniRC

+0

@AruniRC Creo que la solución de @ChaosPandion es mucho mejor que la que usa 'unfold', así que iría con eso :-) –

+0

@AruniRC, el Seq es flojo: para cuando lo evalúes más adelante en el código , es posible que el lector ya esté cerrado, de ahí el 'No se puede leer desde un TextReader cerrado '. Tendrá que forzar la evaluación de la secuencia de inmediato, por ejemplo convirtiendo a la lista con 'Seq.toList', o algún otro truco. –

3

En .NET 2/3 que puede hacer:

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

y en .NET 4:

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

El primero de ellos no es perezoso ('ReadAllLines' ansiosamente lee todas las líneas en una matriz). –

8
let lines = File.ReadLines(path)     

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