La clase File provee un conjunto de métodos para la entrada/salida.
Groovy provides a number of helper methods for working with I/O. All of these work with standard Java Reader3.1/Writer3.2and InputStream3.3/OutputStream3.4and File and URL classes.
generaciondecodigos@nereida:~/src/groovy/files$ cat -n readfile.groovy 1 #!/usr/bin/env groovy 2 /** 3 Reading a text file 4 */ 5 file = args[0] 6 new File(file).eachLine{ line -> 7 println line 8 }
If for whatever reason theprintln()
method were to throw an exception, theeachLine()
method ensures that the file resource is correctly closed. Similarly if an exception occurs while reading, the resource will be closed too.
Ejecución:
generaciondecodigos@nereida:~/src/groovy/files$ ./readfile.groovy readfile.groovy #!/usr/bin/env groovy /** Reading a text file */ file = args[0] new File(file).eachLine{ line -> println line }
El acceso new File(fileName).text
se traduce en una llamada al método getText()
public String getText()El cual lee los contenidos del File y retorna la
String
.
generaciondecodigos@nereida:~/src/groovy/io$ cat -n slurpFile.groovy 1 #!/usr/bin/env groovy 2 // retrieve the content of the file 3 if (!args) return 4 fileName = args[0] 5 content = new File(fileName).text 6 println content
Existe otra forma de llamar a getText
:
String getText(String)que lee los contenidos del File usando la codificación especificada como argumento. En ese caso no es posible acceder via la sintáxis de atributo (
.text
):
generaciondecodigos@nereida:~/src/groovy/io$ cat -n slurpFile2.groovy 1 #!/usr/bin/env groovy 2 // you can specify the encoding of the file 3 // note that since getText() has a parameter, 4 // you cannot call it with something like text("UTF-8") 5 if (!args) return 6 fileName = args[0] 7 content = new File(fileName).getText("UTF-8") 8 9 println content
An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset. The charset that it uses may be specified by name or may be given explicitly, or the platform's default charset may be accepted.
Each invocation of one of an InputStreamReader's
read()
methods may
cause one or more bytes to be read from the underlying byte-input
stream. To enable the efficient conversion of bytes to characters,
more bytes may be read ahead from the underlying stream than are
necessary to satisfy the current read operation.
For top efficiency, consider wrapping an InputStreamReader within a BufferedReader.
~/Lgroovy/files$ cat -n stdin.groovy 1 #!/usr/bin/env groovy 2 prompt = '\n> ' 3 print 'Enter text including a digit:' + prompt 4 new BufferedReader(new InputStreamReader(System.in)).eachLine{ line -> 5 // line is read from System.in 6 if (line =~ '\\d') println "Read: $line" // normal output to System.out 7 else System.err.println 'No digit found.' // this message to System.err 8 }
El atributo in
de la clase System
se refiere al flujo de entrada estandard. Es un objeto
de la clase java.io.BufferedInputStream
.
Del mismo modo existen los atributos out
y err
para referirse a la salida estandard
y al flujo e errores.
The eachLine
method
iterates through the stream, passing each line to the given closure.
Ejecución:
~/Lgroovy/files$ ./stdin.groovy Enter text including a digit: > a3b Read: a3b hjk No digit found. 42 Read: 42 ^D
En realidad System.in
pertenece a la clase java.io.BufferedInputStream
y por tanto
es ya un flujo dotado de un buffer. El anterior programa puede reescribirse:
~/Lgroovy/files$ cat -n readline.groovy 1 #!/usr/bin/env groovy 2 prompt = '\n> ' 3 print 'Enter text including a digit:' + prompt 4 System.in.eachLine{ line -> 5 // line is read from System.in 6 if (line =~ '\\d') println "Read: $line" // normal output to System.out 7 else System.err.println 'No digit found.' // this message to System.err 8 }
El operador a =~ 'regexp'
comprueba si la cadena a
casa/matches con regexp
.
groovy:000> line = "hello world" ===> hello world groovy:000> m = line =~ '[aeiou]' ===> java.util.regex.Matcher[pattern=[aeiou] region=0,11 lastmatch=] groovy:000> m[0] ===> e groovy:000> m[1] ===> o groovy:000> m.size() ===> 3
en un contexto booleano es
evaluado como cierto si la cadena a
pertenece al lenguaje descrito por
la regexp
.
The following table summarizes the rules and the order in which they are applied to evaluate truth in a condition:
Type
Evaluation criteria Boolean
Value is equal to true
Matcher
There is at least one match Collection
The collection is not empty Map
The map is not empty String, GString
The string is not empty Number, Character
The value is not 0 (zero) others
Non null
reference
Remember that the type is determined in runtime, not at compile time.
El siguiente programa muestra la primera ocurrencia de un enlace href
en
cada línea de un fichero HTML:
~/Lgroovy/files$ cat -n links.groovy 1 #!/usr/bin/env groovy 2 if (args.length == 0 ) return 3 testfile = new File(args[0]) 4 testfile.eachLine { line -> 5 line.find(/(?ix) href \s* = \s* "( [^"]* )"/) { 6 delta, link -> println "delta = '$delta' link='$link'" 7 } 8 }
The String methodpublic String find(Pattern pattern, Closure closure)
finds the first occurrence of a compiled regular expressionPattern
within aString
.
If the pattern doesn't match, theclosure
will not be called andfind
will returnnull
.
If it does match and we don't have any capture groups in our regex,
there is a single parameter on the closure
that the match gets
passed to.
If we have capture groups in our expression, our closure
has one parameter for the match, followed by one for each of the capture
groups.
The funtion returns aString
containing the result of theclosure
, ornull
if the regexpattern
doesn't match
Cuando lo ejecutamos obtenemos una salida similar a esta:
~/Lgroovy/files$ ./links.groovy node17.html | head -4 delta = 'HREF = "mystyle.css"' link='mystyle.css' delta = 'HREF="node18.html"' link='node18.html' delta = 'HREF="node16.html"' link='node16.html' delta = 'HREF="node6.html"' link='node6.html'
El método
readLines
nos permite leer un fichero completo y guardarlo en una lista:
groovy:000> f = new File("input.txt") ===> input.txt groovy:000> lines = f.readLines() ===> [an, input, file] groovy:000> lines.class ===> class java.util.ArrayListUsando
readLines
podemos contar las líneas en un fichero:
groovy:000> new File("input.txt").readLines().size() ===> 3
Una vez que los contenidos del fichero se tienen en forma de lista es posible aplicar cualquiera de los métodos de manipulación de listas.
groovy:000> new File('input.txt').readLines().reverse() ===> [file, input, an] groovy:000> new File('input.txt').readLines().sort() ===> [an, file, input]
En el siguiente ejemplo
contaremos el número de párrafos, líneas y apariciones de
la palabra captain
en un fichero de texto:
groovy:000> f = new File("texto") ===> texto groovy:000> f.text ===> Captain my Captain! our fearful trip is done; The ship has weathered every rack, the prize we sought is won; The port is near, the bells I hear, the people all exulting, While follow eyes the steady keel, the vessel grim and daring: But O heart! heart! heart! O the bleeding drops of red, Where on the deck my Captain lies, Fallen cold and dead. O Captain! my Captain! rise up and hear the bells; Rise up—for you the flag is flung—for you the bugle trills; For you bouquets and ribbon’d wreaths—for you the shores a-crowding; For you they call, the swaying mass, their eager faces turning; Here Captain! dear father! This arm beneath your head; It is some dream that on the deck, You’ve fallen cold and dead. My Captain does not answer, his lips are pale and still; My father does not feel my arm, he has no pulse nor will; The ship is anchored safe and sound, its voyage closed and done; From fearful trip, the victor ship, comes in with object won; Exult, O shores, and ring, O bells! But I, with mournful tread, Walk the deck my Captain lies, Fallen cold and dead.Un párrafo se define como texto delimitado entre líneas en blanco:
groovy:000> m = f.text.findAll('\\n\\n+').size() ===> 8El número de líneas es el número de retornos de carro:
groovy:000> m = f.text.findAll('\\n').size() ===> 35Contemos el número de veces que aparece la palabra
Captain
:
m = f.text.findAll('(?i)\\bCaptain\\b').size() ===> 8