001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.io.output;
018
019 import java.io.File;
020 import java.io.FileOutputStream;
021 import java.io.IOException;
022 import java.io.OutputStream;
023 import java.io.OutputStreamWriter;
024 import java.io.Writer;
025 import java.nio.charset.Charset;
026 import java.nio.charset.CharsetEncoder;
027
028 import org.apache.commons.io.FileUtils;
029 import org.apache.commons.io.IOUtils;
030
031 /**
032 * Writer of files that allows the encoding to be set.
033 * <p>
034 * This class provides a simple alternative to <code>FileWriter</code>
035 * that allows an encoding to be set. Unfortunately, it cannot subclass
036 * <code>FileWriter</code>.
037 * <p>
038 * By default, the file will be overwritten, but this may be changed to append.
039 * <p>
040 * The encoding must be specified using either the name of the {@link Charset},
041 * the {@link Charset}, or a {@link CharsetEncoder}. If the default encoding
042 * is required then use the {@link java.io.FileWriter} directly, rather than
043 * this implementation.
044 * <p>
045 *
046 *
047 * @since 1.4
048 * @version $Id: FileWriterWithEncoding.java 1304052 2012-03-22 20:55:29Z ggregory $
049 */
050 public class FileWriterWithEncoding extends Writer {
051 // Cannot extend ProxyWriter, as requires writer to be
052 // known when super() is called
053
054 /** The writer to decorate. */
055 private final Writer out;
056
057 /**
058 * Constructs a FileWriterWithEncoding with a file encoding.
059 *
060 * @param filename the name of the file to write to, not null
061 * @param encoding the encoding to use, not null
062 * @throws NullPointerException if the file name or encoding is null
063 * @throws IOException in case of an I/O error
064 */
065 public FileWriterWithEncoding(String filename, String encoding) throws IOException {
066 this(new File(filename), encoding, false);
067 }
068
069 /**
070 * Constructs a FileWriterWithEncoding with a file encoding.
071 *
072 * @param filename the name of the file to write to, not null
073 * @param encoding the encoding to use, not null
074 * @param append true if content should be appended, false to overwrite
075 * @throws NullPointerException if the file name or encoding is null
076 * @throws IOException in case of an I/O error
077 */
078 public FileWriterWithEncoding(String filename, String encoding, boolean append) throws IOException {
079 this(new File(filename), encoding, append);
080 }
081
082 /**
083 * Constructs a FileWriterWithEncoding with a file encoding.
084 *
085 * @param filename the name of the file to write to, not null
086 * @param encoding the encoding to use, not null
087 * @throws NullPointerException if the file name or encoding is null
088 * @throws IOException in case of an I/O error
089 */
090 public FileWriterWithEncoding(String filename, Charset encoding) throws IOException {
091 this(new File(filename), encoding, false);
092 }
093
094 /**
095 * Constructs a FileWriterWithEncoding with a file encoding.
096 *
097 * @param filename the name of the file to write to, not null
098 * @param encoding the encoding to use, not null
099 * @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 @Override
266 public void write(int idx) throws IOException {
267 out.write(idx);
268 }
269
270 /**
271 * Write the characters from an array.
272 * @param chr the characters to write
273 * @throws IOException if an I/O error occurs
274 */
275 @Override
276 public void write(char[] chr) throws IOException {
277 out.write(chr);
278 }
279
280 /**
281 * Write the specified characters from an array.
282 * @param chr the characters to write
283 * @param st The start offset
284 * @param end The number of characters to write
285 * @throws IOException if an I/O error occurs
286 */
287 @Override
288 public void write(char[] chr, int st, int end) throws IOException {
289 out.write(chr, st, end);
290 }
291
292 /**
293 * Write the characters from a string.
294 * @param str the string to write
295 * @throws IOException if an I/O error occurs
296 */
297 @Override
298 public void write(String str) throws IOException {
299 out.write(str);
300 }
301
302 /**
303 * Write the specified characters from a string.
304 * @param str the string to write
305 * @param st The start offset
306 * @param end The number of characters to write
307 * @throws IOException if an I/O error occurs
308 */
309 @Override
310 public void write(String str, int st, int end) throws IOException {
311 out.write(str, st, end);
312 }
313
314 /**
315 * Flush the stream.
316 * @throws IOException if an I/O error occurs
317 */
318 @Override
319 public void flush() throws IOException {
320 out.flush();
321 }
322
323 /**
324 * Close the stream.
325 * @throws IOException if an I/O error occurs
326 */
327 @Override
328 public void close() throws IOException {
329 out.close();
330 }
331 }