Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Andrey Adamovich - Groovy 2 Cookbook - 2013.pdf
Скачиваний:
44
Добавлен:
19.03.2016
Размер:
26.28 Mб
Скачать

Working with Files in Groovy

The leftShift operator is used again to append data to a stream. The stream object will be opened and closed automatically in a similar way to the withWriter method.

There's more...

You can also wrap file access using the withDataOutputStream and withObjectOutputStream methods. This gives you access to the java.

io.DataOutputStream and java.io.ObjectOutputStream instances

within a closure that allows you to write out primitive and serialized Java types respectively.

If you want to control the writer or stream instances yourself, you can use convenient constructor methods such as newWriter, newOutputStream, newDataOutputStream,

and newObjectOutputStream.

Many of the writing methods of java.io.File are also available in the java.io.Writer and java.io.OutputStream classes that allow using Groovy goodies for virtually any output target.

See also

ff Reading from a file

ff http://groovy.codehaus.org/groovy-jdk/java/io/File.html

ff http://groovy.codehaus.org/groovy-jdk/java/io/Writer.html

ff http://groovy.codehaus.org/groovy-jdk/java/io/OutputStream.html

ff http://groovy.codehaus.org/groovy-jdk/java/io/PrintWriter.html

ff http://groovy.codehaus.org/groovy-jdk/java/io/PrintStream.html

Replacing tabs with spaces in a text file

Searching and replacing file content is an often needed routine that can be automated with the help of Groovy scripts, one of which will be shown in this recipe.

Getting ready

Let's assume that we have an input.txt file that contains some tabulation characters.

We want to replace the tabulation characters with spaces and save the results into a output.txt file.

144

www.it-ebooks.info

Chapter 4

To perform any action on these files (similar to the Filtering a text file's content recipe), we need to create two instances of java.io.File objects:

def inputFile = new File('input.txt') def outputFile = new File('output.txt')

How to do it...

Let's go through several ways to achieve the desired result:

1.First of all, we will take advantage of the transformLine method available in the java.io.Reader class, as well as the withWriter and withReader methods that are described in more detail in the Writing to a file and Reading from a file recipes:

outputFile.withWriter { Writer writer -> inputFile.withReader { Reader reader ->

reader.transformLine(writer) { String line -> line.replaceAll('\t', ' ')

}

}

}

2. A more concise form of the above code snippet looks like this:

inputFile.withReader { reader -> reader.transformLine(outputFile.newWriter()) { line ->

line.replaceAll('\t', ' ')

}

}

3.Another way to do this is with the help of the getText and setText extension methods of java.io.File:

outputFile.text = inputFile.text.replaceAll('\t', ' ')

Although this approach is the shortest one, it has some complications, which we will describe in the next section.

How it works...

Groovy adds an extension method, transformLine, to the java.io.Reader class. We used this method in the first and second examples. The method takes two input parameters, a Writer and a Closure. The closure expects a String and it should return a transformed String back. The writer is used to output the transformed lines. This means that by

having a reader and a writer, we can use transformLine to perform a line-based data transformation.

145

www.it-ebooks.info

Working with Files in Groovy

Since the transformLine method automatically closes the writer, we can omit the outer method call to withWriter and just pass a new Writer instance to the transformLine method. That's what we've shown in the second example we just described.

The previous code snippet, of course, looks more concise; but this approach has one disadvantage. The whole file content will be loaded into the memory, and, in the case of a very large file, we are at risk of getting an OutOfMemoryError exception. With the first and second approaches, we don't risk incurring any memory problems.

You have to choose which approach is more appropriate based on your input file sizes.

There's more...

In a similar way as we used transformLine, you can also use the transformChar method to make character-based input transformations. For example, this code will transform a TAB character with a single space character:

inputFile.withReader { Reader reader -> reader.transformChar(outputFile.newWriter()) { String chr ->

chr == '\t' ? ' ' : chr

}

}

See also

The following recipes give an introduction to I/O operations in Groovy:

ff

ff

Reading from a file Writing to a file

Also, it's worth looking at what additional functionality Groovy offers in the java.io.Reader class:

ff http://groovy.codehaus.org/groovy-jdk/java/io/Reader.html

Filtering a text file's content

Filtering a text file's content is a rather common task. In this recipe, we will show how it can be easily achieved with Groovy.

146

www.it-ebooks.info

Chapter 4

Getting ready

Let's assume we want to filter out comment lines from a Bash script stored in the script.sh file and we want to save it into the new_script.sh file. First of all, we need to define two variables of the java.io.File type that point to our inputFile

and outputFile:

def inputFile = new File('script.sh')

def outputFile = new File('new_script.sh')

How to do it...

File filtering can be implemented in several ways:

1.We can make use of the closure-based methods (that is eachLine and withPrintWriter) that we have got familiar with in the Reading a text file line by line and Writing to a file recipes:

outputFile.withPrintWriter { writer -> inputFile.eachLine { line ->

if (!line.startsWith('#')) { writer.println(line)

}

}

}

2.Another way to achieve the same result is to use a filterLine method. It takes a Writer and a closure as input parameters. The closure gets a string line as an input and should return true or false depending on whether line is filtered in or out.

We can rewrite the original code snippet in the following way:

outputFile.withWriter { writer -> inputFile.filterLine(writer) { line ->

!line.startsWith('#')

}

}

3.Actually, the filterLine method also closes the given writer automatically. So, we can omit one closure from the previous code and just pass a new Writer instance to the method:

inputFile.filterLine(outputFile.newWriter()) { line -> !line.startsWith('#')

}

147

www.it-ebooks.info

Working with Files in Groovy

How it works...

In the first code example above, we have first called a method withPrintWriter to which we passed a closure in which we iterated through text lines with the help of the eachLine method. The inner closure passed to eachLine has access to both the writer and the line objects. Inside that closure, we added a simple conditional statement to write out only those lines that do not start with #.

In the second snippet, we passed a closure to the filterLine method. That closure gives you access to the line and expects to return a boolean that indicates whether that line should be written to the final output (writer) or not.

All code examples achieve the same result. The filtered Bash script should contain no comments after execution of the Groovy code demonstrated in the previous section.

There's more...

There is another overloaded version of the filterLine method that returns an instance

of groovy.lang.Writable. Writable has only one method that is, writeTo(java. io.Writer writer). It's a Groovy abstraction that allows postponing the content creation until it is actually streamed to the final output target. Instances of Writable can be used in most of the output operations such as print, write, append, and leftShift. That's why this filterLine version does not need any Writer. Taking it all into account, we can rewrite the previous code as a one-liner:

outputFile << inputFile.filterLine { !it.startsWith('#') }

The Writable result of the filterLine method is sent to outputFile with the help of the leftShift operator (you can read more about it in Writing to a file recipe). We also omitted the line variable and simply referred to Groovy's default it closure parameter. In this way, the code looks almost similar to an OS command; short and clear.

See also

Check the following recipes for some additional insights:

ff

ff

Reading a text file line by line Writing to a file

The following Groovydoc links may be of interest for the reader:

ff http://groovy.codehaus.org/api/groovy/lang/Writable.html ff http://groovy.codehaus.org/groovy-jdk/java/io/File.html

148

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]