Home | History | Annotate | Download | only in output
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 package org.apache.commons.io.output;
     18 
     19 import java.io.File;
     20 import java.io.FileOutputStream;
     21 import java.io.IOException;
     22 import java.io.OutputStream;
     23 import java.io.OutputStreamWriter;
     24 import java.io.Writer;
     25 import java.nio.charset.Charset;
     26 import java.nio.charset.CharsetEncoder;
     27 
     28 import org.apache.commons.io.FileUtils;
     29 import org.apache.commons.io.IOUtils;
     30 
     31 /**
     32  * Writer of files that allows the encoding to be set.
     33  * <p>
     34  * This class provides a simple alternative to <code>FileWriter</code>
     35  * that allows an encoding to be set. Unfortunately, it cannot subclass
     36  * <code>FileWriter</code>.
     37  * <p>
     38  * By default, the file will be overwritten, but this may be changed to append.
     39  * <p>
     40  * The encoding must be specified using either the name of the {@link Charset},
     41  * the {@link Charset}, or a {@link CharsetEncoder}. If the default encoding
     42  * is required then use the {@link java.io.FileWriter} directly, rather than
     43  * this implementation.
     44  * <p>
     45  *
     46  *
     47  * @since Commons IO 1.4
     48  * @version $Id: FileWriterWithEncoding.java 611634 2008-01-13 20:35:00Z niallp $
     49  */
     50 public class FileWriterWithEncoding extends Writer {
     51     // Cannot extend ProxyWriter, as requires writer to be
     52     // known when super() is called
     53 
     54     /** The writer to decorate. */
     55     private final Writer out;
     56 
     57     /**
     58      * Constructs a FileWriterWithEncoding with a file encoding.
     59      *
     60      * @param filename  the name of the file to write to, not null
     61      * @param encoding  the encoding to use, not null
     62      * @throws NullPointerException if the file name or encoding is null
     63      * @throws IOException in case of an I/O error
     64      */
     65     public FileWriterWithEncoding(String filename, String encoding) throws IOException {
     66         this(new File(filename), encoding, false);
     67     }
     68 
     69     /**
     70      * Constructs a FileWriterWithEncoding with a file encoding.
     71      *
     72      * @param filename  the name of the file to write to, not null
     73      * @param encoding  the encoding to use, not null
     74      * @param append  true if content should be appended, false to overwrite
     75      * @throws NullPointerException if the file name or encoding is null
     76      * @throws IOException in case of an I/O error
     77      */
     78     public FileWriterWithEncoding(String filename, String encoding, boolean append) throws IOException {
     79         this(new File(filename), encoding, append);
     80     }
     81 
     82     /**
     83      * Constructs a FileWriterWithEncoding with a file encoding.
     84      *
     85      * @param filename  the name of the file to write to, not null
     86      * @param encoding  the encoding to use, not null
     87      * @throws NullPointerException if the file name or encoding is null
     88      * @throws IOException in case of an I/O error
     89      */
     90     public FileWriterWithEncoding(String filename, Charset encoding) throws IOException {
     91         this(new File(filename), encoding, false);
     92     }
     93 
     94     /**
     95      * Constructs a FileWriterWithEncoding with a file encoding.
     96      *
     97      * @param filename  the name of the file to write to, not null
     98      * @param encoding  the encoding to use, not null
     99      * @param append  true if content should be appended, false to overwrite
    100      * @throws NullPointerException if the file name or encoding is null
    101      * @throws IOException in case of an I/O error
    102      */
    103     public FileWriterWithEncoding(String filename, Charset encoding, boolean append) throws IOException {
    104         this(new File(filename), encoding, append);
    105     }
    106 
    107     /**
    108      * Constructs a FileWriterWithEncoding with a file encoding.
    109      *
    110      * @param filename  the name of the file to write to, not null
    111      * @param encoding  the encoding to use, not null
    112      * @throws NullPointerException if the file name or encoding is null
    113      * @throws IOException in case of an I/O error
    114      */
    115     public FileWriterWithEncoding(String filename, CharsetEncoder encoding) throws IOException {
    116         this(new File(filename), encoding, false);
    117     }
    118 
    119     /**
    120      * Constructs a FileWriterWithEncoding with a file encoding.
    121      *
    122      * @param filename  the name of the file to write to, not null
    123      * @param encoding  the encoding to use, not null
    124      * @param append  true if content should be appended, false to overwrite
    125      * @throws NullPointerException if the file name or encoding is null
    126      * @throws IOException in case of an I/O error
    127      */
    128     public FileWriterWithEncoding(String filename, CharsetEncoder encoding, boolean append) throws IOException {
    129         this(new File(filename), encoding, append);
    130     }
    131 
    132     /**
    133      * Constructs a FileWriterWithEncoding with a file encoding.
    134      *
    135      * @param file  the file to write to, not null
    136      * @param encoding  the encoding to use, not null
    137      * @throws NullPointerException if the file or encoding is null
    138      * @throws IOException in case of an I/O error
    139      */
    140     public FileWriterWithEncoding(File file, String encoding) throws IOException {
    141         this(file, encoding, false);
    142     }
    143 
    144     /**
    145      * Constructs a FileWriterWithEncoding with a file encoding.
    146      *
    147      * @param file  the file to write to, not null
    148      * @param encoding  the encoding to use, not null
    149      * @param append  true if content should be appended, false to overwrite
    150      * @throws NullPointerException if the file or encoding is null
    151      * @throws IOException in case of an I/O error
    152      */
    153     public FileWriterWithEncoding(File file, String encoding, boolean append) throws IOException {
    154         super();
    155         this.out = initWriter(file, encoding, append);
    156     }
    157 
    158     /**
    159      * Constructs a FileWriterWithEncoding with a file encoding.
    160      *
    161      * @param file  the file to write to, not null
    162      * @param encoding  the encoding to use, not null
    163      * @throws NullPointerException if the file or encoding is null
    164      * @throws IOException in case of an I/O error
    165      */
    166     public FileWriterWithEncoding(File file, Charset encoding) throws IOException {
    167         this(file, encoding, false);
    168     }
    169 
    170     /**
    171      * Constructs a FileWriterWithEncoding with a file encoding.
    172      *
    173      * @param file  the file to write to, not null
    174      * @param encoding  the encoding to use, not null
    175      * @param append  true if content should be appended, false to overwrite
    176      * @throws NullPointerException if the file or encoding is null
    177      * @throws IOException in case of an I/O error
    178      */
    179     public FileWriterWithEncoding(File file, Charset encoding, boolean append) throws IOException {
    180         super();
    181         this.out = initWriter(file, encoding, append);
    182     }
    183 
    184     /**
    185      * Constructs a FileWriterWithEncoding with a file encoding.
    186      *
    187      * @param file  the file to write to, not null
    188      * @param encoding  the encoding to use, not null
    189      * @throws NullPointerException if the file or encoding is null
    190      * @throws IOException in case of an I/O error
    191      */
    192     public FileWriterWithEncoding(File file, CharsetEncoder encoding) throws IOException {
    193         this(file, encoding, false);
    194     }
    195 
    196     /**
    197      * Constructs a FileWriterWithEncoding with a file encoding.
    198      *
    199      * @param file  the file to write to, not null
    200      * @param encoding  the encoding to use, not null
    201      * @param append  true if content should be appended, false to overwrite
    202      * @throws NullPointerException if the file or encoding is null
    203      * @throws IOException in case of an I/O error
    204      */
    205     public FileWriterWithEncoding(File file, CharsetEncoder encoding, boolean append) throws IOException {
    206         super();
    207         this.out = initWriter(file, encoding, append);
    208     }
    209 
    210     //-----------------------------------------------------------------------
    211     /**
    212      * Initialise the wrapped file writer.
    213      * Ensure that a cleanup occurs if the writer creation fails.
    214      *
    215      * @param file  the file to be accessed
    216      * @param encoding  the encoding to use - may be Charset, CharsetEncoder or String
    217      * @param append  true to append
    218      * @return the initialised writer
    219      * @throws NullPointerException if the file or encoding is null
    220      * @throws IOException if an error occurs
    221      */
    222      private static Writer initWriter(File file, Object encoding, boolean append) throws IOException {
    223         if (file == null) {
    224             throw new NullPointerException("File is missing");
    225         }
    226         if (encoding == null) {
    227             throw new NullPointerException("Encoding is missing");
    228         }
    229         boolean fileExistedAlready = file.exists();
    230         OutputStream stream = null;
    231         Writer writer = null;
    232         try {
    233             stream = new FileOutputStream(file, append);
    234             if (encoding instanceof Charset) {
    235                 writer = new OutputStreamWriter(stream, (Charset)encoding);
    236             } else if (encoding instanceof CharsetEncoder) {
    237                 writer = new OutputStreamWriter(stream, (CharsetEncoder)encoding);
    238             } else {
    239                 writer = new OutputStreamWriter(stream, (String)encoding);
    240             }
    241         } catch (IOException ex) {
    242             IOUtils.closeQuietly(writer);
    243             IOUtils.closeQuietly(stream);
    244             if (fileExistedAlready == false) {
    245                 FileUtils.deleteQuietly(file);
    246             }
    247             throw ex;
    248         } catch (RuntimeException ex) {
    249             IOUtils.closeQuietly(writer);
    250             IOUtils.closeQuietly(stream);
    251             if (fileExistedAlready == false) {
    252                 FileUtils.deleteQuietly(file);
    253             }
    254             throw ex;
    255         }
    256         return writer;
    257     }
    258 
    259     //-----------------------------------------------------------------------
    260     /**
    261      * Write a character.
    262      * @param idx the character to write
    263      * @throws IOException if an I/O error occurs
    264      */
    265     public void write(int idx) throws IOException {
    266         out.write(idx);
    267     }
    268 
    269     /**
    270      * Write the characters from an array.
    271      * @param chr the characters to write
    272      * @throws IOException if an I/O error occurs
    273      */
    274     public void write(char[] chr) throws IOException {
    275         out.write(chr);
    276     }
    277 
    278     /**
    279      * Write the specified characters from an array.
    280      * @param chr the characters to write
    281      * @param st The start offset
    282      * @param end The number of characters to write
    283      * @throws IOException if an I/O error occurs
    284      */
    285     public void write(char[] chr, int st, int end) throws IOException {
    286         out.write(chr, st, end);
    287     }
    288 
    289     /**
    290      * Write the characters from a string.
    291      * @param str the string to write
    292      * @throws IOException if an I/O error occurs
    293      */
    294     public void write(String str) throws IOException {
    295         out.write(str);
    296     }
    297 
    298     /**
    299      * Write the specified characters from a string.
    300      * @param str the string to write
    301      * @param st The start offset
    302      * @param end The number of characters to write
    303      * @throws IOException if an I/O error occurs
    304      */
    305     public void write(String str, int st, int end) throws IOException {
    306         out.write(str, st, end);
    307     }
    308 
    309     /**
    310      * Flush the stream.
    311      * @throws IOException if an I/O error occurs
    312      */
    313     public void flush() throws IOException {
    314         out.flush();
    315     }
    316 
    317     /**
    318      * Close the stream.
    319      * @throws IOException if an I/O error occurs
    320      */
    321     public void close() throws IOException {
    322         out.close();
    323     }
    324 }
    325