Leyendo y escribiendo archivos

Quizás una de las tareas principales de todo código es leer (y escribir) información en archivos. Para ello F# utiliza en su base las funciones que el ecosistema .NET ofrece, con numerosas alternativas. Veamos algunas de ellas:

let fileName = "../data/El reloj de arena.txt"


let readFile (fileName: string) =  
    let lines = File.ReadAllLines(fileName)
    lines 
let lines = readFile fileName 

La función ReadAllLines devuelve una secuencia, donde cada línea es un elemento:

lines
|> Seq.iteri (fun i l -> printfn "%d: %s" i l)
0: El reloj de arena 
1: JLB
2: 
3: Está bien que se mida con la dura
4: Sombra que una columna en el estío
5: Arroja o con el agua de aquel río
6: En que Heráclito vio nuestra locura
7: 
8: El tiempo, ya que al tiempo y al destino
9: Se parecen los dos: la imponderable
10: Sombra diurna y el curso irrevocable
11: Del agua que prosigue su camino.
12: 
13: Está bien, pero el tiempo en los desiertos
14: Otra substancia halló, suave y pesada,
15: Que parece haber sido imaginada
16: Para medir el tiempo de los muertos.
17: 
18: Surge así el alegórico instrumento
19: De los grabados de los diccionarios,
20: La pieza que los grises anticuarios
21: Relegarán al mundo ceniciento
22: 
23: Del alfil desparejo, de la espada
24: Inerme, del borroso telescopio,
25: Del sándalo mordido por el opio
26: Del polvo, del azar y de la nada.
27: 
28: ¿Quién no se ha demorado ante el severo
29: Y tétrico instrumento que acompaña
30: En la diestra del dios a la guadaña
31: Y cuyas líneas repitió Durero?
32: 
33: Por el ápice abierto el cono inverso
34: Deja caer la cautelosa arena,
35: Oro gradual que se desprende y llena
36: El cóncavo cristal de su universo.
37: 
38: Hay un agrado en observar la arcana
39: Arena que resbala y que declina
40: Y, a punto de caer, se arremolina
41: Con una prisa que es del todo humana.
42: 
43: La arena de los ciclos es la misma
44: E infinita es la historia de la arena;
45: Así, bajo tus dichas o tu pena,
46: La invulnerable eternidad se abisma.
47: 
48: No se detiene nunca la caída
49: Yo me desangro, no el cristal. El rito
50: De decantar la arena es infinito
51: Y con la arena se nos va la vida.
52: 
53: En los minutos de la arena creo
54: Sentir el tiempo cósmico: la historia
55: Que encierra en sus espejos la memoria
56: O que ha disuelto el mágico Leteo.
57: 
58: El pilar de humo y el pilar de fuego,
59: Cartago y Roma y su apretada guerra,
60: Simón Mago, los siete pies de tierra
61: Que el rey sajón ofrece al rey noruego,
62: 
63: Todo lo arrastra y pierde este incansable
64: Hilo sutil de arena numerosa.
65: No he de salvarme yo, fortuita cosa
66: De tiempo, que es materia deleznable.
lines
|> Seq.where (fun l -> l.Contains("tiempo"))
|> Seq.iteri (fun i l -> printfn "%d: %s" i l)
0: El tiempo, ya que al tiempo y al destino
1: Está bien, pero el tiempo en los desiertos
2: Para medir el tiempo de los muertos.
3: Sentir el tiempo cósmico: la historia
4: De tiempo, que es materia deleznable.

Utilizando algunos métodos de seq, podemos procesar el poema y separarlo en estrofas:

lines
|> Seq.skip 3
|> Seq.chunkBySize 5
|> Seq.map (fun estrofa ->
                estrofa 
                |> Seq.where (fun verso -> not (String.IsNullOrEmpty(verso)))
                )
|> Seq.mapi (fun i e -> (i+1,e))
|> Seq.iter (fun (i,l) -> printfn "%d: %A" i l)
1: seq
  ["Está bien que se mida con la dura"; "Sombra que una columna en el estío";
   "Arroja o con el agua de aquel río"; "En que Heráclito vio nuestra locura"]
2: seq
  ["El tiempo, ya que al tiempo y al destino";
   "Se parecen los dos: la imponderable"; "Sombra diurna y el curso irrevocable";
   "Del agua que prosigue su camino."]
3: seq
  ["Está bien, pero el tiempo en los desiertos";
   "Otra substancia halló, suave y pesada,"; "Que parece haber sido imaginada";
   "Para medir el tiempo de los muertos."]
4: seq
  ["Surge así el alegórico instrumento"; "De los grabados de los diccionarios,";
   "La pieza que los grises anticuarios"; "Relegarán al mundo ceniciento"]
5: seq
  ["Del alfil desparejo, de la espada"; "Inerme, del borroso telescopio,";
   "Del sándalo mordido por el opio"; "Del polvo, del azar y de la nada."]
6: seq
  ["¿Quién no se ha demorado ante el severo";
   "Y tétrico instrumento que acompaña"; "En la diestra del dios a la guadaña";
   "Y cuyas líneas repitió Durero?"]
7: seq
  ["Por el ápice abierto el cono inverso"; "Deja caer la cautelosa arena,";
   "Oro gradual que se desprende y llena"; "El cóncavo cristal de su universo."]
8: seq
  ["Hay un agrado en observar la arcana"; "Arena que resbala y que declina";
   "Y, a punto de caer, se arremolina"; "Con una prisa que es del todo humana."]
9: seq
  ["La arena de los ciclos es la misma";
   "E infinita es la historia de la arena;"; "Así, bajo tus dichas o tu pena,";
   "La invulnerable eternidad se abisma."]
10: seq
  ["No se detiene nunca la caída"; "Yo me desangro, no el cristal. El rito";
   "De decantar la arena es infinito"; "Y con la arena se nos va la vida."]
11: seq
  ["En los minutos de la arena creo"; "Sentir el tiempo cósmico: la historia";
   "Que encierra en sus espejos la memoria";
   "O que ha disuelto el mágico Leteo."]
12: seq
  ["El pilar de humo y el pilar de fuego,";
   "Cartago y Roma y su apretada guerra,";
   "Simón Mago, los siete pies de tierra";
   "Que el rey sajón ofrece al rey noruego,"]
13: seq
  ["Todo lo arrastra y pierde este incansable"; "Hilo sutil de arena numerosa.";
   "No he de salvarme yo, fortuita cosa";
   "De tiempo, que es materia deleznable."]

A diferencia de ReadAllLines, la función ReadAllText lee el archivo como un string

let readFileAsTxt (fileName: string) =  
    let lines = File.ReadAllText(fileName)
    lines 
let poema = readFileAsTxt fileName
printfn "%A" poema
"El reloj de arena 
JLB

Está bien que se mida con la dura
Sombra que una columna en el estío
Arroja o con el agua de aquel río
En que Heráclito vio nuestra locura

El tiempo, ya que al tiempo y al destino
Se parecen los dos: la imponderable
Sombra diurna y el curso irrevocable
Del agua que prosigue su camino.

Está bien, pero el tiempo en los desiertos
Otra substancia halló, suave y pesada,
Que parece haber sido imaginada
Para medir el tiempo de los muertos.

Surge así el alegórico instrumento
De los grabados de los diccionarios,
La pieza que los grises anticuarios
Relegarán al mundo ceniciento

Del alfil desparejo, de la espada
Inerme, del borroso telescopio,
Del sándalo mordido por el opio
Del polvo, del azar y de la nada.

¿Quién no se ha demorado ante el severo
Y tétrico instrumento que acompaña
En la diestra del dios a la guadaña
Y cuyas líneas repitió Durero?

Por el ápice abierto el cono inverso
Deja caer la cautelosa arena,
Oro gradual que se desprende y llena
El cóncavo cristal de su universo.

Hay un agrado en observar la arcana
Arena que resbala y que declina
Y, a punto de caer, se arremolina
Con una prisa que es del todo humana.

La arena de los ciclos es la misma
E infinita es la historia de la arena;
Así, bajo tus dichas o tu pena,
La invulnerable eternidad se abisma.

No se detiene nunca la caída
Yo me desangro, no el cristal. El rito
De decantar la arena es infinito
Y con la arena se nos va la vida.

En los minutos de la arena creo
Sentir el tiempo cósmico: la historia
Que encierra en sus espejos la memoria
O que ha disuelto el mágico Leteo.

El pilar de humo y el pilar de fuego,
Cartago y Roma y su apretada guerra,
Simón Mago, los siete pies de tierra
Que el rey sajón ofrece al rey noruego,

Todo lo arrastra y pierde este incansable
Hilo sutil de arena numerosa.
No he de salvarme yo, fortuita cosa
De tiempo, que es materia deleznable."

Entonces, podemos usar el método Split del módulo System.String para separar el texto en versos usando el caracter \n (final de línea):

let p = poema.Split("\n")
printfn "%A" p
[|"El reloj de arena "; "JLB"; ""; "Está bien que se mida con la dura";
  "Sombra que una columna en el estío"; "Arroja o con el agua de aquel río";
  "En que Heráclito vio nuestra locura"; "";
  "El tiempo, ya que al tiempo y al destino";
  "Se parecen los dos: la imponderable"; "Sombra diurna y el curso irrevocable";
  "Del agua que prosigue su camino."; "";
  "Está bien, pero el tiempo en los desiertos";
  "Otra substancia halló, suave y pesada,"; "Que parece haber sido imaginada";
  "Para medir el tiempo de los muertos."; "";
  "Surge así el alegórico instrumento"; "De los grabados de los diccionarios,";
  "La pieza que los grises anticuarios"; "Relegarán al mundo ceniciento"; "";
  "Del alfil desparejo, de la espada"; "Inerme, del borroso telescopio,";
  "Del sándalo mordido por el opio"; "Del polvo, del azar y de la nada."; "";
  "¿Quién no se ha demorado ante el severo";
  "Y tétrico instrumento que acompaña"; "En la diestra del dios a la guadaña";
  "Y cuyas líneas repitió Durero?"; ""; "Por el ápice abierto el cono inverso";
  "Deja caer la cautelosa arena,"; "Oro gradual que se desprende y llena";
  "El cóncavo cristal de su universo."; "";
  "Hay un agrado en observar la arcana"; "Arena que resbala y que declina";
  "Y, a punto de caer, se arremolina"; "Con una prisa que es del todo humana.";
  ""; "La arena de los ciclos es la misma";
  "E infinita es la historia de la arena;"; "Así, bajo tus dichas o tu pena,";
  "La invulnerable eternidad se abisma."; ""; "No se detiene nunca la caída";
  "Yo me desangro, no el cristal. El rito"; "De decantar la arena es infinito";
  "Y con la arena se nos va la vida."; ""; "En los minutos de la arena creo";
  "Sentir el tiempo cósmico: la historia";
  "Que encierra en sus espejos la memoria"; "O que ha disuelto el mágico Leteo.";
  ""; "El pilar de humo y el pilar de fuego,";
  "Cartago y Roma y su apretada guerra,"; "Simón Mago, los siete pies de tierra";
  "Que el rey sajón ofrece al rey noruego,"; "";
  "Todo lo arrastra y pierde este incansable"; "Hilo sutil de arena numerosa.";
  "No he de salvarme yo, fortuita cosa"; "De tiempo, que es materia deleznable."|]

Escribiendo en archivos

Vamos a editar un poco el poema para que se pueda ver como Markdown.

let poemaConFormato =
    lines
    |> Seq.map (fun l -> l.Replace("tiempo","_tiempo_")) // Cambiamos tiempo por itálica

poemaConFormato
|> Seq.iter (fun v -> printfn "%s" v)
El reloj de arena 
JLB

Está bien que se mida con la dura
Sombra que una columna en el estío
Arroja o con el agua de aquel río
En que Heráclito vio nuestra locura

El _tiempo_, ya que al _tiempo_ y al destino
Se parecen los dos: la imponderable
Sombra diurna y el curso irrevocable
Del agua que prosigue su camino.

Está bien, pero el _tiempo_ en los desiertos
Otra substancia halló, suave y pesada,
Que parece haber sido imaginada
Para medir el _tiempo_ de los muertos.

Surge así el alegórico instrumento
De los grabados de los diccionarios,
La pieza que los grises anticuarios
Relegarán al mundo ceniciento

Del alfil desparejo, de la espada
Inerme, del borroso telescopio,
Del sándalo mordido por el opio
Del polvo, del azar y de la nada.

¿Quién no se ha demorado ante el severo
Y tétrico instrumento que acompaña
En la diestra del dios a la guadaña
Y cuyas líneas repitió Durero?

Por el ápice abierto el cono inverso
Deja caer la cautelosa arena,
Oro gradual que se desprende y llena
El cóncavo cristal de su universo.

Hay un agrado en observar la arcana
Arena que resbala y que declina
Y, a punto de caer, se arremolina
Con una prisa que es del todo humana.

La arena de los ciclos es la misma
E infinita es la historia de la arena;
Así, bajo tus dichas o tu pena,
La invulnerable eternidad se abisma.

No se detiene nunca la caída
Yo me desangro, no el cristal. El rito
De decantar la arena es infinito
Y con la arena se nos va la vida.

En los minutos de la arena creo
Sentir el _tiempo_ cósmico: la historia
Que encierra en sus espejos la memoria
O que ha disuelto el mágico Leteo.

El pilar de humo y el pilar de fuego,
Cartago y Roma y su apretada guerra,
Simón Mago, los siete pies de tierra
Que el rey sajón ofrece al rey noruego,

Todo lo arrastra y pierde este incansable
Hilo sutil de arena numerosa.
No he de salvarme yo, fortuita cosa
De _tiempo_, que es materia deleznable.
File.WriteAllLines("../El reloj de arena.md",poemaConFormato2)

Para que quede escrito tal cual poema, tendríamos que agregar una línea vacía entre cada verso, porque una estrofa tal como está en el archivo quedaría así

El tiempo, ya que al tiempo y al destino Se parecen los dos: la imponderable Sombra diurna y el curso irrevocable Del agua que prosigue su camino.

Una manera es intercalar una línea vacía entre cada verso:

let poemaConFormato2 =
    lines
    |> Seq.map (fun l -> l.Replace("tiempo","_tiempo_"))
    |> Seq.map (fun l -> seq {l ; ""})
    |> Seq.concat

poemaConFormato2
|> Seq.iter (fun v -> printfn "%s" v)    

El reloj de arena 

JLB



Está bien que se mida con la dura

Sombra que una columna en el estío

Arroja o con el agua de aquel río

En que Heráclito vio nuestra locura



El _tiempo_, ya que al _tiempo_ y al destino

Se parecen los dos: la imponderable

Sombra diurna y el curso irrevocable

Del agua que prosigue su camino.



Está bien, pero el _tiempo_ en los desiertos

Otra substancia halló, suave y pesada,

Que parece haber sido imaginada

Para medir el _tiempo_ de los muertos.



Surge así el alegórico instrumento

De los grabados de los diccionarios,

La pieza que los grises anticuarios

Relegarán al mundo ceniciento



Del alfil desparejo, de la espada

Inerme, del borroso telescopio,

Del sándalo mordido por el opio

Del polvo, del azar y de la nada.



¿Quién no se ha demorado ante el severo

Y tétrico instrumento que acompaña

En la diestra del dios a la guadaña

Y cuyas líneas repitió Durero?



Por el ápice abierto el cono inverso

Deja caer la cautelosa arena,

Oro gradual que se desprende y llena

El cóncavo cristal de su universo.



Hay un agrado en observar la arcana

Arena que resbala y que declina

Y, a punto de caer, se arremolina

Con una prisa que es del todo humana.



La arena de los ciclos es la misma

E infinita es la historia de la arena;

Así, bajo tus dichas o tu pena,

La invulnerable eternidad se abisma.



No se detiene nunca la caída

Yo me desangro, no el cristal. El rito

De decantar la arena es infinito

Y con la arena se nos va la vida.



En los minutos de la arena creo

Sentir el _tiempo_ cósmico: la historia

Que encierra en sus espejos la memoria

O que ha disuelto el mágico Leteo.



El pilar de humo y el pilar de fuego,

Cartago y Roma y su apretada guerra,

Simón Mago, los siete pies de tierra

Que el rey sajón ofrece al rey noruego,



Todo lo arrastra y pierde este incansable

Hilo sutil de arena numerosa.

No he de salvarme yo, fortuita cosa

De _tiempo_, que es materia deleznable.

O, siguiendo estas instrucciones, agregar dos espacios al final del texto.

let poemaConFormato3 =
    lines
    |> Seq.map (fun l -> l.Replace("tiempo","_tiempo_"))
    |> Seq.map (fun l -> l + "  ")

File.WriteAllLines("../data/El reloj de arena 2.md",poemaConFormato3)

Para aprender más sobre IO, pueden ver este blog de Ángel Muñoz.

results matching ""

    No results matching ""