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 */ 17package org.apache.commons.io.output; 18 19import java.io.File; 20import java.io.FileOutputStream; 21import java.io.IOException; 22import java.io.OutputStream; 23import java.io.OutputStreamWriter; 24import java.io.Writer; 25import java.nio.charset.Charset; 26import java.nio.charset.CharsetEncoder; 27 28import org.apache.commons.io.FileUtils; 29import 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 */ 50public 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