Author: niallp
Date: Mon Jan  7 20:20:00 2008
New Revision: 609864

URL: http://svn.apache.org/viewvc?rev=609864&view=rev
Log:
IO-153 Add a FileWriter that accepts an encoding - patch from Stephen Colebourne

Added:
    
commons/proper/io/trunk/src/java/org/apache/commons/io/output/FileWriterWithEncoding.java
   (with props)
    
commons/proper/io/trunk/src/test/org/apache/commons/io/output/FileWriterWithEncodingTest.java
   (with props)
Modified:
    commons/proper/io/trunk/RELEASE-NOTES.txt
    commons/proper/io/trunk/build-check-jdk13.xml
    
commons/proper/io/trunk/src/test/org/apache/commons/io/output/PackageTestSuite.java

Modified: commons/proper/io/trunk/RELEASE-NOTES.txt
URL: 
http://svn.apache.org/viewvc/commons/proper/io/trunk/RELEASE-NOTES.txt?rev=609864&r1=609863&r2=609864&view=diff
==============================================================================
--- commons/proper/io/trunk/RELEASE-NOTES.txt (original)
+++ commons/proper/io/trunk/RELEASE-NOTES.txt Mon Jan  7 20:20:00 2008
@@ -24,9 +24,9 @@
 Semantic compatible - Yes
   Check the bug fixes section for semantic bug fixes
 
-Commons IO 1.4 introduces some new implementations which depend on JDK 1.4
-features (CharSequenceReader, IOExceptionWithCause and RegexFileFilter). It has
-been built with the JDK source and target options set to JDK 1.3 and, except 
for
+Commons IO 1.4 introduces four new implementations which depend on JDK 1.4 
features
+(CharSequenceReader, FileWriterWithEncoding, IOExceptionWithCause and 
RegexFileFilter).
+It has been built with the JDK source and target options set to JDK 1.3 and, 
except for
 those implementations, can be used with JDK 1.3 (see IO IO-127).
 
 
@@ -52,6 +52,9 @@
 
 - TeeInputStream [IO-129]
   - Add new Tee input stream implementation
+
+- FileWriterWithEncoding [IO-153]
+  - Add new File Writer implementation that accepts an encoding
 
 - CharSequenceReader [IO-138]
   - Add new Reader implementation that handles any CharSequence (String,

Modified: commons/proper/io/trunk/build-check-jdk13.xml
URL: 
http://svn.apache.org/viewvc/commons/proper/io/trunk/build-check-jdk13.xml?rev=609864&r1=609863&r2=609864&view=diff
==============================================================================
--- commons/proper/io/trunk/build-check-jdk13.xml (original)
+++ commons/proper/io/trunk/build-check-jdk13.xml Mon Jan  7 20:20:00 2008
@@ -64,6 +64,7 @@
             <exclude name="**/CharSequenceReader.java"/>
             <exclude name="**/IOExceptionWithCause.java"/>
             <exclude name="**/RegexFileFilter.java"/>
+            <exclude name="**/FileWriterWithEncoding.java"/>
 
         </javac>
 

Added: 
commons/proper/io/trunk/src/java/org/apache/commons/io/output/FileWriterWithEncoding.java
URL: 
http://svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/apache/commons/io/output/FileWriterWithEncoding.java?rev=609864&view=auto
==============================================================================
--- 
commons/proper/io/trunk/src/java/org/apache/commons/io/output/FileWriterWithEncoding.java
 (added)
+++ 
commons/proper/io/trunk/src/java/org/apache/commons/io/output/FileWriterWithEncoding.java
 Mon Jan  7 20:20:00 2008
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.io.output;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+/**
+ * Writer of files that allows the encoding to be set.
+ * <p>
+ * This class provides a simple alternative to <code>FileWriter</code>
+ * that allows an encoding to be set. Unfortunately, it cannot subclass
+ * <code>FileWriter</code>.
+ * <p>
+ * By default, the file will be overwritten, but this may be changed to append.
+ * The encoding may also be specified, and defaults to the platform default.
+ *
+ * @since Commons IO 1.4
+ * @version $Id$
+ */
+public class FileWriterWithEncoding extends Writer {
+    // Cannot extend ProxyWriter, as requires writer to be
+    // known when super() is called
+
+    /** The writer to decorate. */
+    private final Writer out;
+
+    /**
+     * Constructs a FileWriterWithEncoding with a file encoding.
+     *
+     * @param filename  the name of the file to write to, not null
+     * @param encoding  the encoding to use, not null
+     * @throws NullPointerException if the file name or encoding is null
+     * @throws IOException in case of an I/O error
+     */
+    public FileWriterWithEncoding(String filename, String encoding) throws 
IOException {
+        this(new File(filename), encoding, false);
+    }
+
+    /**
+     * Constructs a FileWriterWithEncoding with a file encoding.
+     *
+     * @param filename  the name of the file to write to, not null
+     * @param encoding  the encoding to use, not null
+     * @param append  true if content should be appended, false to overwrite
+     * @throws NullPointerException if the file name or encoding is null
+     * @throws IOException in case of an I/O error
+     */
+    public FileWriterWithEncoding(String filename, String encoding, boolean 
append) throws IOException {
+        this(new File(filename), encoding, append);
+    }
+
+    /**
+     * Constructs a FileWriterWithEncoding with a file encoding.
+     *
+     * @param filename  the name of the file to write to, not null
+     * @param encoding  the encoding to use, not null
+     * @throws NullPointerException if the file name or encoding is null
+     * @throws IOException in case of an I/O error
+     */
+    public FileWriterWithEncoding(String filename, Charset encoding) throws 
IOException {
+        this(new File(filename), encoding, false);
+    }
+
+    /**
+     * Constructs a FileWriterWithEncoding with a file encoding.
+     *
+     * @param filename  the name of the file to write to, not null
+     * @param encoding  the encoding to use, not null
+     * @param append  true if content should be appended, false to overwrite
+     * @throws NullPointerException if the file name or encoding is null
+     * @throws IOException in case of an I/O error
+     */
+    public FileWriterWithEncoding(String filename, Charset encoding, boolean 
append) throws IOException {
+        this(new File(filename), encoding, append);
+    }
+
+    /**
+     * Constructs a FileWriterWithEncoding with a file encoding.
+     *
+     * @param filename  the name of the file to write to, not null
+     * @param encoding  the encoding to use, not null
+     * @throws NullPointerException if the file name or encoding is null
+     * @throws IOException in case of an I/O error
+     */
+    public FileWriterWithEncoding(String filename, CharsetEncoder encoding) 
throws IOException {
+        this(new File(filename), encoding, false);
+    }
+
+    /**
+     * Constructs a FileWriterWithEncoding with a file encoding.
+     *
+     * @param filename  the name of the file to write to, not null
+     * @param encoding  the encoding to use, not null
+     * @param append  true if content should be appended, false to overwrite
+     * @throws NullPointerException if the file name or encoding is null
+     * @throws IOException in case of an I/O error
+     */
+    public FileWriterWithEncoding(String filename, CharsetEncoder encoding, 
boolean append) throws IOException {
+        this(new File(filename), encoding, append);
+    }
+
+    /**
+     * Constructs a FileWriterWithEncoding with a file encoding.
+     *
+     * @param file  the file to write to, not null
+     * @param encoding  the encoding to use, not null
+     * @throws NullPointerException if the file or encoding is null
+     * @throws IOException in case of an I/O error
+     */
+    public FileWriterWithEncoding(File file, String encoding) throws 
IOException {
+        this(file, encoding, false);
+    }
+
+    /**
+     * Constructs a FileWriterWithEncoding with a file encoding.
+     *
+     * @param file  the file to write to, not null
+     * @param encoding  the encoding to use, not null
+     * @param append  true if content should be appended, false to overwrite
+     * @throws NullPointerException if the file or encoding is null
+     * @throws IOException in case of an I/O error
+     */
+    public FileWriterWithEncoding(File file, String encoding, boolean append) 
throws IOException {
+        super();
+        this.out = initWriter(file, encoding, append);
+    }
+
+    /**
+     * Constructs a FileWriterWithEncoding with a file encoding.
+     *
+     * @param file  the file to write to, not null
+     * @param encoding  the encoding to use, not null
+     * @throws NullPointerException if the file or encoding is null
+     * @throws IOException in case of an I/O error
+     */
+    public FileWriterWithEncoding(File file, Charset encoding) throws 
IOException {
+        this(file, encoding, false);
+    }
+
+    /**
+     * Constructs a FileWriterWithEncoding with a file encoding.
+     *
+     * @param file  the file to write to, not null
+     * @param encoding  the encoding to use, not null
+     * @param append  true if content should be appended, false to overwrite
+     * @throws NullPointerException if the file or encoding is null
+     * @throws IOException in case of an I/O error
+     */
+    public FileWriterWithEncoding(File file, Charset encoding, boolean append) 
throws IOException {
+        super();
+        this.out = initWriter(file, encoding, append);
+    }
+
+    /**
+     * Constructs a FileWriterWithEncoding with a file encoding.
+     *
+     * @param file  the file to write to, not null
+     * @param encoding  the encoding to use, not null
+     * @throws NullPointerException if the file or encoding is null
+     * @throws IOException in case of an I/O error
+     */
+    public FileWriterWithEncoding(File file, CharsetEncoder encoding) throws 
IOException {
+        this(file, encoding, false);
+    }
+
+    /**
+     * Constructs a FileWriterWithEncoding with a file encoding.
+     *
+     * @param file  the file to write to, not null
+     * @param encoding  the encoding to use, not null
+     * @param append  true if content should be appended, false to overwrite
+     * @throws NullPointerException if the file or encoding is null
+     * @throws IOException in case of an I/O error
+     */
+    public FileWriterWithEncoding(File file, CharsetEncoder encoding, boolean 
append) throws IOException {
+        super();
+        this.out = initWriter(file, encoding, append);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Initialise the wrapped file writer.
+     * Ensure that a cleanup occurs if the writer creation fails.
+     *
+     * @param file  the file to be accessed
+     * @param encoding  the encoding to use - may be Charset, CharsetEncoder 
or String
+     * @param append  true to append
+     * @return the initialised writer
+     * @throws NullPointerException if the file or encoding is null
+     * @throws IOException if an error occurs
+     */
+     private static Writer initWriter(File file, Object encoding, boolean 
append) throws IOException {
+        if (file == null) {
+            throw new NullPointerException("File is missing");
+        }
+        if (encoding == null) {
+            throw new NullPointerException("Encoding is missing");
+        }
+        boolean fileExistedAlready = file.exists();
+        OutputStream stream = null;
+        Writer writer = null;
+        try {
+            stream = new FileOutputStream(file, append);
+            if (encoding instanceof Charset) {
+                writer = new OutputStreamWriter(stream, (Charset)encoding);
+            } else if (encoding instanceof CharsetEncoder) {
+                writer = new OutputStreamWriter(stream, 
(CharsetEncoder)encoding);
+            } else {
+                writer = new OutputStreamWriter(stream, (String)encoding);
+            }
+        } catch (IOException ex) {
+            IOUtils.closeQuietly(writer);
+            IOUtils.closeQuietly(stream);
+            if (fileExistedAlready == false) {
+                FileUtils.deleteQuietly(file);
+            }
+            throw ex;
+        } catch (RuntimeException ex) {
+            IOUtils.closeQuietly(writer);
+            IOUtils.closeQuietly(stream);
+            if (fileExistedAlready == false) {
+                FileUtils.deleteQuietly(file);
+            }
+            throw ex;
+        }
+        return writer;
+    }
+
+    //-----------------------------------------------------------------------
+    /** @see java.io.Writer#write(int) */
+    public void write(int idx) throws IOException {
+        out.write(idx);
+    }
+
+    /** @see java.io.Writer#write(char[]) */
+    public void write(char[] chr) throws IOException {
+        out.write(chr);
+    }
+
+    /** @see java.io.Writer#write(char[], int, int) */
+    public void write(char[] chr, int st, int end) throws IOException {
+        out.write(chr, st, end);
+    }
+
+    /** @see java.io.Writer#write(String) */
+    public void write(String str) throws IOException {
+        out.write(str);
+    }
+
+    /** @see java.io.Writer#write(String, int, int) */
+    public void write(String str, int st, int end) throws IOException {
+        out.write(str, st, end);
+    }
+
+    /** @see java.io.Writer#flush() */
+    public void flush() throws IOException {
+        out.flush();
+    }
+
+    /** @see java.io.Writer#close() */
+    public void close() throws IOException {
+        out.close();
+    }
+}

Propchange: 
commons/proper/io/trunk/src/java/org/apache/commons/io/output/FileWriterWithEncoding.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/io/trunk/src/java/org/apache/commons/io/output/FileWriterWithEncoding.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: 
commons/proper/io/trunk/src/test/org/apache/commons/io/output/FileWriterWithEncodingTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/org/apache/commons/io/output/FileWriterWithEncodingTest.java?rev=609864&view=auto
==============================================================================
--- 
commons/proper/io/trunk/src/test/org/apache/commons/io/output/FileWriterWithEncodingTest.java
 (added)
+++ 
commons/proper/io/trunk/src/test/org/apache/commons/io/output/FileWriterWithEncodingTest.java
 Mon Jan  7 20:20:00 2008
@@ -0,0 +1,221 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.io.output;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.Map;
+
+import junit.framework.AssertionFailedError;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.testtools.FileBasedTestCase;
+
+/**
+ * Tests that the encoding is actually set and used.
+ *
+ * @version $Revision$ $Date$
+ */
+public class FileWriterWithEncodingTest extends FileBasedTestCase {
+
+    private String defaultEncoding;
+    private File file1;
+    private File file2;
+    private String textContent;
+
+    public FileWriterWithEncodingTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        File encodingFinder = new File(getTestDirectory(), "finder.txt");
+        OutputStreamWriter out = null;
+        try {
+            out = new OutputStreamWriter(new FileOutputStream(encodingFinder));
+            defaultEncoding = out.getEncoding();
+        } catch (IOException ex) {
+            throw new RuntimeException(ex.getMessage());
+        } finally {
+            IOUtils.closeQuietly(out);
+        }
+        file1 = new File(getTestDirectory(), "testfile1.txt");
+        file2 = new File(getTestDirectory(), "testfile2.txt");
+        char[] arr = new char[1024];
+        for (int i = 0; i < arr.length; i++) {
+            arr[i] = (char) i;
+        }
+        textContent = new String(arr);
+    }
+
+    public void tearDown() {
+        defaultEncoding = null;
+        file1.delete();
+        file2.delete();
+        textContent = null;
+    }
+
+    //-----------------------------------------------------------------------
+    public void testSameEncoding() throws Exception {
+        FileWriter fw1 = null;
+        FileWriterWithEncoding fw2 = null;
+        try {
+            fw1 = new FileWriter(file1);  // default encoding
+            fw2 = new FileWriterWithEncoding(file2, defaultEncoding);
+            assertEquals(true, file1.exists());
+            assertEquals(true, file2.exists());
+            
+            fw1.write(textContent);
+            fw2.write(textContent);
+            
+            fw1.flush();
+            fw2.flush();
+            checkFile(file1, file2);
+            
+        } finally {
+            IOUtils.closeQuietly(fw1);
+            IOUtils.closeQuietly(fw2);
+        }
+        assertEquals(true, file1.exists());
+        assertEquals(true, file2.exists());
+    }
+
+    public void testDifferentEncoding() throws Exception {
+        Map map = Charset.availableCharsets();
+        if (map.containsKey("UTF-16BE")) {
+            FileWriter fw1 = null;
+            FileWriterWithEncoding fw2 = null;
+            try {
+                fw1 = new FileWriter(file1);  // default encoding
+                fw2 = new FileWriterWithEncoding(file2, defaultEncoding);
+                assertEquals(true, file1.exists());
+                assertEquals(true, file2.exists());
+                
+                fw1.write(textContent);
+                fw2.write(textContent);
+                
+                fw1.flush();
+                fw2.flush();
+                try {
+                    checkFile(file1, file2);
+                    fail();
+                } catch (AssertionFailedError ex) {
+                    // success
+                }
+                
+            } finally {
+                IOUtils.closeQuietly(fw1);
+                IOUtils.closeQuietly(fw2);
+            }
+            assertEquals(true, file1.exists());
+            assertEquals(true, file2.exists());
+        }
+        if (map.containsKey("UTF-16LE")) {
+            FileWriter fw1 = null;
+            FileWriterWithEncoding fw2 = null;
+            try {
+                fw1 = new FileWriter(file1);  // default encoding
+                fw2 = new FileWriterWithEncoding(file2, defaultEncoding);
+                assertEquals(true, file1.exists());
+                assertEquals(true, file2.exists());
+                
+                fw1.write(textContent);
+                fw2.write(textContent);
+                
+                fw1.flush();
+                fw2.flush();
+                try {
+                    checkFile(file1, file2);
+                    fail();
+                } catch (AssertionFailedError ex) {
+                    // success
+                }
+                
+            } finally {
+                IOUtils.closeQuietly(fw1);
+                IOUtils.closeQuietly(fw2);
+            }
+            assertEquals(true, file1.exists());
+            assertEquals(true, file2.exists());
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    public void testConstructor_File_encoding_badEncoding() throws IOException 
{
+        Writer writer = null;
+        try {
+            writer = new FileWriterWithEncoding(file1, "BAD-ENCODE");
+            fail();
+        } catch (IOException ex) {
+            // expected
+            assertEquals(false, file1.exists());
+        } finally {
+            IOUtils.closeQuietly(writer);
+        }
+        assertEquals(false, file1.exists());
+    }
+
+    //-----------------------------------------------------------------------
+    public void testConstructor_File_directory() throws IOException {
+        Writer writer = null;
+        try {
+            writer = new FileWriterWithEncoding(getTestDirectory(), 
defaultEncoding);
+            fail();
+        } catch (IOException ex) {
+            // expected
+            assertEquals(false, file1.exists());
+        } finally {
+            IOUtils.closeQuietly(writer);
+        }
+        assertEquals(false, file1.exists());
+    }
+
+    //-----------------------------------------------------------------------
+    public void testConstructor_File_nullFile() throws IOException {
+        Writer writer = null;
+        try {
+            writer = new FileWriterWithEncoding((File) null, defaultEncoding);
+            fail();
+        } catch (NullPointerException ex) {
+            // expected
+            assertEquals(false, file1.exists());
+        } finally {
+            IOUtils.closeQuietly(writer);
+        }
+        assertEquals(false, file1.exists());
+    }
+
+    //-----------------------------------------------------------------------
+    public void testConstructor_fileName_nullFile() throws IOException {
+        Writer writer = null;
+        try {
+            writer = new FileWriterWithEncoding((String) null, 
defaultEncoding);
+            fail();
+        } catch (NullPointerException ex) {
+            // expected
+            assertEquals(false, file1.exists());
+        } finally {
+            IOUtils.closeQuietly(writer);
+        }
+        assertEquals(false, file1.exists());
+    }
+
+}

Propchange: 
commons/proper/io/trunk/src/test/org/apache/commons/io/output/FileWriterWithEncodingTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/io/trunk/src/test/org/apache/commons/io/output/FileWriterWithEncodingTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: 
commons/proper/io/trunk/src/test/org/apache/commons/io/output/PackageTestSuite.java
URL: 
http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/org/apache/commons/io/output/PackageTestSuite.java?rev=609864&r1=609863&r2=609864&view=diff
==============================================================================
--- 
commons/proper/io/trunk/src/test/org/apache/commons/io/output/PackageTestSuite.java
 (original)
+++ 
commons/proper/io/trunk/src/test/org/apache/commons/io/output/PackageTestSuite.java
 Mon Jan  7 20:20:00 2008
@@ -38,6 +38,7 @@
         suite.addTest(new TestSuite(CloseShieldOutputStreamTest.class));
         suite.addTest(new TestSuite(CountingOutputStreamTest.class));
         suite.addTest(new TestSuite(DeferredFileOutputStreamTest.class));
+        suite.addTest(new TestSuite(FileWriterWithEncodingTest.class));
         suite.addTest(new TestSuite(LockableFileWriterTest.class));
         suite.addTest(new TestSuite(NullOutputStreamTest.class));
         suite.addTest(new TestSuite(NullWriterTest.class));


Reply via email to