Home | History | Annotate | Download | only in io
      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 
     18 package java.io;
     19 
     20 import java.util.Arrays;
     21 
     22 /**
     23  * A specialized {@link Writer} for class for writing content to an (internal)
     24  * char array. As bytes are written to this writer, the char array may be
     25  * expanded to hold more characters. When the writing is considered to be
     26  * finished, a copy of the char array can be requested from the class.
     27  *
     28  * @see CharArrayReader
     29  */
     30 public class CharArrayWriter extends Writer {
     31 
     32     /**
     33      * The buffer for characters.
     34      */
     35     protected char[] buf;
     36 
     37     /**
     38      * The ending index of the buffer.
     39      */
     40     protected int count;
     41 
     42     /**
     43      * Constructs a new {@code CharArrayWriter} which has a buffer allocated
     44      * with the default size of 32 characters. This buffer is also used as the
     45      * {@code lock} to synchronize access to this writer.
     46      */
     47     public CharArrayWriter() {
     48         buf = new char[32];
     49         lock = buf;
     50     }
     51 
     52     /**
     53      * Constructs a new {@code CharArrayWriter} which has a buffer allocated
     54      * with the size of {@code initialSize} characters. The buffer is also used
     55      * as the {@code lock} to synchronize access to this writer.
     56      *
     57      * @param initialSize
     58      *            the initial size of this CharArrayWriters buffer.
     59      * @throws IllegalArgumentException
     60      *             if {@code initialSize < 0}.
     61      */
     62     public CharArrayWriter(int initialSize) {
     63         if (initialSize < 0) {
     64             throw new IllegalArgumentException("size < 0");
     65         }
     66         buf = new char[initialSize];
     67         lock = buf;
     68     }
     69 
     70     /**
     71      * Closes this writer. The implementation in {@code CharArrayWriter} does nothing.
     72      */
     73     @Override
     74     public void close() {
     75         /* empty */
     76     }
     77 
     78     private void expand(int i) {
     79         /* Can the buffer handle @i more chars, if not expand it */
     80         if (count + i <= buf.length) {
     81             return;
     82         }
     83 
     84         int newLen = Math.max(2 * buf.length, count + i);
     85         char[] newbuf = new char[newLen];
     86         System.arraycopy(buf, 0, newbuf, 0, count);
     87         buf = newbuf;
     88     }
     89 
     90     /**
     91      * Flushes this writer. The implementation in {@code CharArrayWriter} does nothing.
     92      */
     93     @Override
     94     public void flush() {
     95         /* empty */
     96     }
     97 
     98     /**
     99      * Resets this writer. The current write position is reset to the beginning
    100      * of the buffer. All written characters are lost and the size of this
    101      * writer is set to 0.
    102      */
    103     public void reset() {
    104         synchronized (lock) {
    105             count = 0;
    106         }
    107     }
    108 
    109     /**
    110      * Returns the size of this writer, that is the number of characters it
    111      * stores. This number changes if this writer is reset or when more
    112      * characters are written to it.
    113      *
    114      * @return this CharArrayWriter's current size in characters.
    115      */
    116     public int size() {
    117         synchronized (lock) {
    118             return count;
    119         }
    120     }
    121 
    122     /**
    123      * Returns the contents of the receiver as a char array. The array returned
    124      * is a copy and any modifications made to this writer after calling this
    125      * method are not reflected in the result.
    126      *
    127      * @return this CharArrayWriter's contents as a new char array.
    128      */
    129     public char[] toCharArray() {
    130         synchronized (lock) {
    131             char[] result = new char[count];
    132             System.arraycopy(buf, 0, result, 0, count);
    133             return result;
    134         }
    135     }
    136 
    137     /**
    138      * Returns the contents of this {@code CharArrayWriter} as a string. The
    139      * string returned is a copy and any modifications made to this writer after
    140      * calling this method are not reflected in the result.
    141      *
    142      * @return this CharArrayWriters contents as a new string.
    143      */
    144     @Override
    145     public String toString() {
    146         synchronized (lock) {
    147             return new String(buf, 0, count);
    148         }
    149     }
    150 
    151     /**
    152      * Writes {@code count} characters starting at {@code offset} in {@code c}
    153      * to this writer.
    154      *
    155      * @param buffer
    156      *            the non-null array containing characters to write.
    157      * @param offset
    158      *            the index of the first character in {@code buf} to write.
    159      * @param len
    160      *            maximum number of characters to write.
    161      * @throws IndexOutOfBoundsException
    162      *             if {@code offset < 0} or {@code len < 0}, or if
    163      *             {@code offset + len} is bigger than the size of {@code c}.
    164      */
    165     @Override
    166     public void write(char[] buffer, int offset, int len) {
    167         Arrays.checkOffsetAndCount(buffer.length, offset, len);
    168         synchronized (lock) {
    169             expand(len);
    170             System.arraycopy(buffer, offset, this.buf, this.count, len);
    171             this.count += len;
    172         }
    173     }
    174 
    175     /**
    176      * Writes the specified character {@code oneChar} to this writer.
    177      * This implementation writes the two low order bytes of the integer
    178      * {@code oneChar} to the buffer.
    179      *
    180      * @param oneChar
    181      *            the character to write.
    182      */
    183     @Override
    184     public void write(int oneChar) {
    185         synchronized (lock) {
    186             expand(1);
    187             buf[count++] = (char) oneChar;
    188         }
    189     }
    190 
    191     /**
    192      * Writes {@code count} characters starting at {@code offset} from
    193      * the string {@code str} to this CharArrayWriter.
    194      *
    195      * @throws NullPointerException
    196      *             if {@code str} is {@code null}.
    197      * @throws StringIndexOutOfBoundsException
    198      *             if {@code offset < 0} or {@code count < 0}, or if
    199      *             {@code offset + count} is bigger than the length of
    200      *             {@code str}.
    201      */
    202     @Override
    203     public void write(String str, int offset, int count) {
    204         if (str == null) {
    205             throw new NullPointerException("str == null");
    206         }
    207         if ((offset | count) < 0 || offset > str.length() - count) {
    208             throw new StringIndexOutOfBoundsException(str, offset, count);
    209         }
    210         synchronized (lock) {
    211             expand(count);
    212             str.getChars(offset, offset + count, buf, this.count);
    213             this.count += count;
    214         }
    215     }
    216 
    217     /**
    218      * Writes the contents of this {@code CharArrayWriter} to another {@code
    219      * Writer}. The output is all the characters that have been written to the
    220      * receiver since the last reset or since it was created.
    221      *
    222      * @param out
    223      *            the non-null {@code Writer} on which to write the contents.
    224      * @throws NullPointerException
    225      *             if {@code out} is {@code null}.
    226      * @throws IOException
    227      *             if an error occurs attempting to write out the contents.
    228      */
    229     public void writeTo(Writer out) throws IOException {
    230         synchronized (lock) {
    231             out.write(buf, 0, count);
    232         }
    233     }
    234 
    235     /**
    236      * Appends a char {@code c} to the {@code CharArrayWriter}. The method works
    237      * the same way as {@code write(c)}.
    238      *
    239      * @param c
    240      *            the character appended to the CharArrayWriter.
    241      * @return this CharArrayWriter.
    242      */
    243     @Override
    244     public CharArrayWriter append(char c) {
    245         write(c);
    246         return this;
    247     }
    248 
    249     /**
    250      * Appends a {@code CharSequence} to the {@code CharArrayWriter}. The method
    251      * works the same way as {@code write(csq.toString())}. If {@code csq} is
    252      * {@code null}, then it will be substituted with the string {@code "null"}.
    253      *
    254      * @param csq
    255      *            the {@code CharSequence} appended to the {@code
    256      *            CharArrayWriter}, may be {@code null}.
    257      * @return this CharArrayWriter.
    258      */
    259     @Override
    260     public CharArrayWriter append(CharSequence csq) {
    261         if (csq == null) {
    262             csq = "null";
    263         }
    264         append(csq, 0, csq.length());
    265         return this;
    266     }
    267 
    268     /**
    269      * Append a subsequence of a {@code CharSequence} to the {@code
    270      * CharArrayWriter}. The first and last characters of the subsequence are
    271      * specified by the parameters {@code start} and {@code end}. A call to
    272      * {@code CharArrayWriter.append(csq)} works the same way as {@code
    273      * CharArrayWriter.write(csq.subSequence(start, end).toString)}. If {@code
    274      * csq} is {@code null}, then it will be substituted with the string {@code
    275      * "null"}.
    276      *
    277      * @param csq
    278      *            the {@code CharSequence} appended to the {@code
    279      *            CharArrayWriter}, may be {@code null}.
    280      * @param start
    281      *            the index of the first character in the {@code CharSequence}
    282      *            appended to the {@code CharArrayWriter}.
    283      * @param end
    284      *            the index of the character after the last one in the {@code
    285      *            CharSequence} appended to the {@code CharArrayWriter}.
    286      * @return this CharArrayWriter.
    287      * @throws IndexOutOfBoundsException
    288      *             if {@code start < 0}, {@code end < 0}, {@code start > end},
    289      *             or if {@code end} is greater than the length of {@code csq}.
    290      */
    291     @Override
    292     public CharArrayWriter append(CharSequence csq, int start, int end) {
    293         if (csq == null) {
    294             csq = "null";
    295         }
    296         String output = csq.subSequence(start, end).toString();
    297         write(output, 0, output.length());
    298         return this;
    299     }
    300 }
    301