Java's I/O API demands a lot of "ceremony code" to cover the file output operations (and actually any other I/O resource). Groovy adds several extensions and syntax sugar to hide Java's complexity and make the code more concise than its Java counterpart. In this recipe, we will cover the file writing methods that are available in Groovy.
To start writing to a file, you just need to create an instance of java.io.File
, for example:
File file = new File('output.txt')
Now let's see which writing operations we can perform on a File
object.
String
you can use the setText
extension method of the java.io.File
(or just Groovy's syntax for property assignment):file.text = 'Just a text'
file.text = '''What's in a name? That which we call a rose By any other name would smell as sweet.'''
setBytes
method:file.bytes = [ 65, 66, 67, 68 ] as byte[]
file.append('What's in a name? That which we call a rose, ') file.append('By any other name would smell as sweet.')
leftShift
operator (<<
).file << 'What's in a name? That which we call a rose ' file << 'By any other name would smell as sweet.'
java.io.Writer
with the help of the withWriter
method:file.withWriter { Writer writer -> writer << 'What's in a name? That which we call a rose ' writer << 'By any other name would smell as sweet.' }
withOutputStream
:file.withOutputStream { OutputStream stream -> stream << 'What's in a name? That which we call a rose ' stream << 'By any other name would smell as sweet.' }
In the first and second code snippets, we used the setText
method. It is actually absolutely equivalent to the write
method that also replaces the file content with the string that is passed. Those methods exist to give the developer the freedom to choose the best wording to describe his or her intent.
The functionality of the leftShift
method is exactly the same as for the append
method. We used both in steps 4 and 5. There are other special method names in Groovy such as plus
for +
or minus
for -
, which you can add to your own classes to be able to write more concise expressions with the help of well-known arithmetical operators.
Each call to the append
or leftShift
methods opens and closes the file every time you execute them. That's, of course, not very efficient if you need to perform many write operations. To get more control, you can operate on the java.io.Writer
object within a closure passed to the withWriter
method that we used in the sixth example.
As you might have noticed, we also make use of the left shift (<<
) operator on the writer
object. That operator is made available by Groovy on all the java.io.Writer
instances, just like with java.io.File
, and even with java.io.OutputStream
.
The withWriter
method creates a new instance of java.io.BufferedWriter
and ensures it is flushed and closed upon return. The file content will be fully replaced. In a similar way, you can use the withWriterAppend
method to use the writer
object to add content to the end of the file. Another available method is withPrintWriter
, which gives you access to the java.io.PrintWriter
instance within a closure.
Another way of writing to a file implies using the withOutputStream
method, which is similar to withWriter
with the exception that the closure operates on the java.io.BufferedOutputStream
instance as you can see in the seventh snippet.
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.
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.