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.nio.charset.Charset;
     21 import java.nio.charset.IllegalCharsetNameException;
     22 import java.util.Arrays;
     23 import java.util.Formatter;
     24 import java.util.IllegalFormatException;
     25 import java.util.Locale;
     26 
     27 /**
     28  * Wraps an existing {@link OutputStream} and provides convenience methods for
     29  * writing common data types in a human readable format. This is not to be
     30  * confused with DataOutputStream which is used for encoding common data types
     31  * so that they can be read back in. No {@code IOException} is thrown by this
     32  * class. Instead, callers should use {@link #checkError()} to see if a problem
     33  * has occurred in this stream.
     34  */
     35 public class PrintStream extends FilterOutputStream implements Appendable, Closeable {
     36     /**
     37      * indicates whether or not this PrintStream has incurred an error.
     38      */
     39     private boolean ioError;
     40 
     41     /**
     42      * indicates whether or not this PrintStream should flush its contents after
     43      * printing a new line.
     44      */
     45     private boolean autoFlush;
     46 
     47     private String encoding;
     48 
     49     /**
     50      * Constructs a new {@code PrintStream} with {@code out} as its target
     51      * stream. By default, the new print stream does not automatically flush its
     52      * contents to the target stream when a newline is encountered.
     53      *
     54      * @param out
     55      *            the target output stream.
     56      * @throws NullPointerException
     57      *             if {@code out} is {@code null}.
     58      */
     59     public PrintStream(OutputStream out) {
     60         super(out);
     61         if (out == null) {
     62             throw new NullPointerException("out == null");
     63         }
     64     }
     65 
     66     /**
     67      * Constructs a new {@code PrintStream} with {@code out} as its target
     68      * stream. The parameter {@code autoFlush} determines if the print stream
     69      * automatically flushes its contents to the target stream when a newline is
     70      * encountered.
     71      *
     72      * @param out
     73      *            the target output stream.
     74      * @param autoFlush
     75      *            indicates whether to flush contents upon encountering a
     76      *            newline sequence.
     77      * @throws NullPointerException
     78      *             if {@code out} is {@code null}.
     79      */
     80     public PrintStream(OutputStream out, boolean autoFlush) {
     81         super(out);
     82         if (out == null) {
     83             throw new NullPointerException("out == null");
     84         }
     85         this.autoFlush = autoFlush;
     86     }
     87 
     88     /**
     89      * Constructs a new {@code PrintStream} with {@code out} as its target
     90      * stream and using the character encoding {@code charsetName} while writing. The
     91      * parameter {@code autoFlush} determines if the print stream automatically
     92      * flushes its contents to the target stream when a newline is encountered.
     93      *
     94      * @param out
     95      *            the target output stream.
     96      * @param autoFlush
     97      *            indicates whether or not to flush contents upon encountering a
     98      *            newline sequence.
     99      * @param charsetName
    100      *            the non-null string describing the desired character encoding.
    101      * @throws NullPointerException
    102      *             if {@code out} or {@code charsetName} are {@code null}.
    103      * @throws UnsupportedEncodingException
    104      *             if the encoding specified by {@code charsetName} is not supported.
    105      */
    106     public PrintStream(OutputStream out, boolean autoFlush, String charsetName)
    107             throws UnsupportedEncodingException {
    108         super(out);
    109         if (out == null) {
    110             throw new NullPointerException("out == null");
    111         } else if (charsetName == null) {
    112             throw new NullPointerException("charsetName == null");
    113         }
    114         this.autoFlush = autoFlush;
    115         try {
    116             if (!Charset.isSupported(charsetName)) {
    117                 throw new UnsupportedEncodingException(charsetName);
    118             }
    119         } catch (IllegalCharsetNameException e) {
    120             throw new UnsupportedEncodingException(charsetName);
    121         }
    122         encoding = charsetName;
    123     }
    124 
    125     /**
    126      * Constructs a new {@code PrintStream} with {@code file} as its target. The
    127      * VM's default character set is used for character encoding.
    128      *
    129      * @param file
    130      *            the target file. If the file already exists, its contents are
    131      *            removed, otherwise a new file is created.
    132      * @throws FileNotFoundException
    133      *             if an error occurs while opening or creating the target file.
    134      */
    135     public PrintStream(File file) throws FileNotFoundException {
    136         super(new FileOutputStream(file));
    137     }
    138 
    139     /**
    140      * Constructs a new {@code PrintStream} with {@code file} as its target. The
    141      * character set named {@code charsetName} is used for character encoding.
    142      *
    143      * @param file
    144      *            the target file. If the file already exists, its contents are
    145      *            removed, otherwise a new file is created.
    146      * @param charsetName
    147      *            the name of the character set used for character encoding.
    148      * @throws FileNotFoundException
    149      *             if an error occurs while opening or creating the target file.
    150      * @throws NullPointerException
    151      *             if {@code charsetName} is {@code null}.
    152      * @throws UnsupportedEncodingException
    153      *             if the encoding specified by {@code charsetName} is not supported.
    154      */
    155     public PrintStream(File file, String charsetName) throws FileNotFoundException,
    156             UnsupportedEncodingException {
    157         super(new FileOutputStream(file));
    158         if (charsetName == null) {
    159             throw new NullPointerException("charsetName == null");
    160         }
    161         if (!Charset.isSupported(charsetName)) {
    162             throw new UnsupportedEncodingException(charsetName);
    163         }
    164         encoding = charsetName;
    165     }
    166 
    167     /**
    168      * Constructs a new {@code PrintStream} with the file identified by
    169      * {@code fileName} as its target. The VM's default character
    170      * set is used for character encoding.
    171      *
    172      * @param fileName
    173      *            the target file's name. If the file already exists, its
    174      *            contents are removed, otherwise a new file is created.
    175      * @throws FileNotFoundException
    176      *             if an error occurs while opening or creating the target file.
    177      */
    178     public PrintStream(String fileName) throws FileNotFoundException {
    179         this(new File(fileName));
    180     }
    181 
    182     /**
    183      * Constructs a new {@code PrintStream} with the file identified by
    184      * {@code fileName} as its target. The character set named {@code charsetName} is
    185      * used for character encoding.
    186      *
    187      * @param fileName
    188      *            the target file's name. If the file already exists, its
    189      *            contents are removed, otherwise a new file is created.
    190      * @param charsetName
    191      *            the name of the character set used for character encoding.
    192      * @throws FileNotFoundException
    193      *             if an error occurs while opening or creating the target file.
    194      * @throws NullPointerException
    195      *             if {@code charsetName} is {@code null}.
    196      * @throws UnsupportedEncodingException
    197      *             if the encoding specified by {@code charsetName} is not supported.
    198      */
    199     public PrintStream(String fileName, String charsetName)
    200             throws FileNotFoundException, UnsupportedEncodingException {
    201         this(new File(fileName), charsetName);
    202     }
    203 
    204     /**
    205      * Flushes this stream and returns the value of the error flag.
    206      *
    207      * @return {@code true} if either an {@code IOException} has been thrown
    208      *         previously or if {@code setError()} has been called;
    209      *         {@code false} otherwise.
    210      * @see #setError()
    211      */
    212     public boolean checkError() {
    213         OutputStream delegate = out;
    214         if (delegate == null) {
    215             return ioError;
    216         }
    217 
    218         flush();
    219         return ioError || delegate.checkError();
    220     }
    221 
    222     /**
    223      * Sets the error state of the stream to false.
    224      * @since 1.6
    225      */
    226     protected void clearError() {
    227         ioError = false;
    228     }
    229 
    230     /**
    231      * Closes this print stream. Flushes this stream and then closes the target
    232      * stream. If an I/O error occurs, this stream's error state is set to
    233      * {@code true}.
    234      */
    235     @Override
    236     public synchronized void close() {
    237         flush();
    238         if (out != null) {
    239             try {
    240                 out.close();
    241                 out = null;
    242             } catch (IOException e) {
    243                 setError();
    244             }
    245         }
    246     }
    247 
    248     /**
    249      * Ensures that all pending data is sent out to the target stream. It also
    250      * flushes the target stream. If an I/O error occurs, this stream's error
    251      * state is set to {@code true}.
    252      */
    253     @Override
    254     public synchronized void flush() {
    255         if (out != null) {
    256             try {
    257                 out.flush();
    258                 return;
    259             } catch (IOException e) {
    260                 // Ignored, fall through to setError
    261             }
    262         }
    263         setError();
    264     }
    265 
    266     /**
    267      * Formats {@code args} according to the format string {@code format}, and writes the result
    268      * to this stream. This method uses the user's default locale.
    269      * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
    270      *
    271      * @param format the format string (see {@link java.util.Formatter#format})
    272      * @param args
    273      *            the list of arguments passed to the formatter. If there are
    274      *            more arguments than required by {@code format},
    275      *            additional arguments are ignored.
    276      * @return this stream.
    277      * @throws IllegalFormatException
    278      *             if the format string is illegal or incompatible with the
    279      *             arguments, if there are not enough arguments or if any other
    280      *             error regarding the format string or arguments is detected.
    281      * @throws NullPointerException if {@code format == null}
    282      */
    283     public PrintStream format(String format, Object... args) {
    284         return format(Locale.getDefault(), format, args);
    285     }
    286 
    287     /**
    288      * Writes a string formatted by an intermediate {@link Formatter} to this
    289      * stream using the specified locale, format string and arguments.
    290      *
    291      * @param l
    292      *            the locale used in the method. No localization will be applied
    293      *            if {@code l} is {@code null}.
    294      * @param format the format string (see {@link java.util.Formatter#format})
    295      * @param args
    296      *            the list of arguments passed to the formatter. If there are
    297      *            more arguments than required by {@code format},
    298      *            additional arguments are ignored.
    299      * @return this stream.
    300      * @throws IllegalFormatException
    301      *             if the format string is illegal or incompatible with the
    302      *             arguments, if there are not enough arguments or if any other
    303      *             error regarding the format string or arguments is detected.
    304      * @throws NullPointerException if {@code format == null}
    305      */
    306     public PrintStream format(Locale l, String format, Object... args) {
    307         if (format == null) {
    308             throw new NullPointerException("format == null");
    309         }
    310         new Formatter(this, l).format(format, args);
    311         return this;
    312     }
    313 
    314     /**
    315      * Prints a formatted string. The behavior of this method is the same as
    316      * this stream's {@code #format(String, Object...)} method.
    317      *
    318      * <p>The {@code Locale} used is the user's default locale.
    319      * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
    320      *
    321      * @param format the format string (see {@link java.util.Formatter#format})
    322      * @param args
    323      *            the list of arguments passed to the formatter. If there are
    324      *            more arguments than required by {@code format},
    325      *            additional arguments are ignored.
    326      * @return this stream.
    327      * @throws IllegalFormatException
    328      *             if the format string is illegal or incompatible with the
    329      *             arguments, if there are not enough arguments or if any other
    330      *             error regarding the format string or arguments is detected.
    331      * @throws NullPointerException if {@code format == null}
    332      */
    333     public PrintStream printf(String format, Object... args) {
    334         return format(format, args);
    335     }
    336 
    337     /**
    338      * Prints a formatted string. The behavior of this method is the same as
    339      * this stream's {@code #format(Locale, String, Object...)} method.
    340      *
    341      * @param l
    342      *            the locale used in the method. No localization will be applied
    343      *            if {@code l} is {@code null}.
    344      * @param format the format string (see {@link java.util.Formatter#format})
    345      * @param args
    346      *            the list of arguments passed to the formatter. If there are
    347      *            more arguments than required by {@code format},
    348      *            additional arguments are ignored.
    349      * @return this stream.
    350      * @throws IllegalFormatException
    351      *             if the format string is illegal or incompatible with the
    352      *             arguments, if there are not enough arguments or if any other
    353      *             error regarding the format string or arguments is detected.
    354      * @throws NullPointerException if {@code format == null}.
    355      */
    356     public PrintStream printf(Locale l, String format, Object... args) {
    357         return format(l, format, args);
    358     }
    359 
    360     /**
    361      * Put the line separator String onto the print stream.
    362      */
    363     private void newline() {
    364         print(System.lineSeparator());
    365     }
    366 
    367     /**
    368      * Prints the string representation of the character array {@code chars}.
    369      */
    370     public void print(char[] chars) {
    371         print(new String(chars, 0, chars.length));
    372     }
    373 
    374     /**
    375      * Prints the string representation of the char {@code c}.
    376      */
    377     public void print(char c) {
    378         print(String.valueOf(c));
    379     }
    380 
    381     /**
    382      * Prints the string representation of the double {@code d}.
    383      */
    384     public void print(double d) {
    385         print(String.valueOf(d));
    386     }
    387 
    388     /**
    389      * Prints the string representation of the float {@code f}.
    390      */
    391     public void print(float f) {
    392         print(String.valueOf(f));
    393     }
    394 
    395     /**
    396      * Prints the string representation of the int {@code i}.
    397      */
    398     public void print(int i) {
    399         print(String.valueOf(i));
    400     }
    401 
    402     /**
    403      * Prints the string representation of the long {@code l}.
    404      */
    405     public void print(long l) {
    406         print(String.valueOf(l));
    407     }
    408 
    409     /**
    410      * Prints the string representation of the Object {@code o}, or {@code "null"}.
    411      */
    412     public void print(Object o) {
    413         print(String.valueOf(o));
    414     }
    415 
    416     /**
    417      * Prints a string to the target stream. The string is converted to an array
    418      * of bytes using the encoding chosen during the construction of this
    419      * stream. The bytes are then written to the target stream with
    420      * {@code write(int)}.
    421      *
    422      * <p>If an I/O error occurs, this stream's error state is set to {@code true}.
    423      *
    424      * @param str
    425      *            the string to print to the target stream.
    426      * @see #write(int)
    427      */
    428     public synchronized void print(String str) {
    429         if (out == null) {
    430             setError();
    431             return;
    432         }
    433         if (str == null) {
    434             print("null");
    435             return;
    436         }
    437 
    438         try {
    439             if (encoding == null) {
    440                 write(str.getBytes());
    441             } else {
    442                 write(str.getBytes(encoding));
    443             }
    444         } catch (IOException e) {
    445             setError();
    446         }
    447     }
    448 
    449     /**
    450      * Prints the string representation of the boolean {@code b}.
    451      */
    452     public void print(boolean b) {
    453         print(String.valueOf(b));
    454     }
    455 
    456     /**
    457      * Prints a newline.
    458      */
    459     public void println() {
    460         newline();
    461     }
    462 
    463     /**
    464      * Prints the string representation of the character array {@code chars} followed by a newline.
    465      */
    466     public void println(char[] chars) {
    467         println(new String(chars, 0, chars.length));
    468     }
    469 
    470     /**
    471      * Prints the string representation of the char {@code c} followed by a newline.
    472      */
    473     public void println(char c) {
    474         println(String.valueOf(c));
    475     }
    476 
    477     /**
    478      * Prints the string representation of the double {@code d} followed by a newline.
    479      */
    480     public void println(double d) {
    481         println(String.valueOf(d));
    482     }
    483 
    484     /**
    485      * Prints the string representation of the float {@code f} followed by a newline.
    486      */
    487    public void println(float f) {
    488         println(String.valueOf(f));
    489     }
    490 
    491    /**
    492      * Prints the string representation of the int {@code i} followed by a newline.
    493      */
    494     public void println(int i) {
    495         println(String.valueOf(i));
    496     }
    497 
    498     /**
    499      * Prints the string representation of the long {@code l} followed by a newline.
    500      */
    501     public void println(long l) {
    502         println(String.valueOf(l));
    503     }
    504 
    505     /**
    506      * Prints the string representation of the Object {@code o}, or {@code "null"},
    507      * followed by a newline.
    508      */
    509     public void println(Object o) {
    510         println(String.valueOf(o));
    511     }
    512 
    513     /**
    514      * Prints a string followed by a newline. The string is converted to an array of bytes using
    515      * the encoding chosen during the construction of this stream. The bytes are
    516      * then written to the target stream with {@code write(int)}.
    517      *
    518      * <p>If an I/O error occurs, this stream's error state is set to {@code true}.
    519      *
    520      * @param str
    521      *            the string to print to the target stream.
    522      * @see #write(int)
    523      */
    524     public synchronized void println(String str) {
    525         print(str);
    526         newline();
    527     }
    528 
    529     /**
    530      * Prints the string representation of the boolean {@code b} followed by a newline.
    531      */
    532     public void println(boolean b) {
    533         println(String.valueOf(b));
    534     }
    535 
    536     /**
    537      * Sets the error flag of this print stream to true.
    538      */
    539     protected void setError() {
    540         ioError = true;
    541     }
    542 
    543     /**
    544      * Writes {@code count} bytes from {@code buffer} starting at {@code offset}
    545      * to the target stream. If autoFlush is set, this stream gets flushed after
    546      * writing the buffer.
    547      *
    548      * <p>This stream's error flag is set to {@code true} if this stream is closed
    549      * or an I/O error occurs.
    550      *
    551      * @param buffer
    552      *            the buffer to be written.
    553      * @param offset
    554      *            the index of the first byte in {@code buffer} to write.
    555      * @param length
    556      *            the number of bytes in {@code buffer} to write.
    557      * @throws IndexOutOfBoundsException
    558      *             if {@code offset < 0} or {@code count < 0}, or if {@code
    559      *             offset + count} is bigger than the length of {@code buffer}.
    560      * @see #flush()
    561      */
    562     @Override
    563     public void write(byte[] buffer, int offset, int length) {
    564         Arrays.checkOffsetAndCount(buffer.length, offset, length);
    565         synchronized (this) {
    566             if (out == null) {
    567                 setError();
    568                 return;
    569             }
    570             try {
    571                 out.write(buffer, offset, length);
    572                 if (autoFlush) {
    573                     flush();
    574                 }
    575             } catch (IOException e) {
    576                 setError();
    577             }
    578         }
    579     }
    580 
    581     /**
    582      * Writes one byte to the target stream. Only the least significant byte of
    583      * the integer {@code oneByte} is written. This stream is flushed if
    584      * {@code oneByte} is equal to the character {@code '\n'} and this stream is
    585      * set to autoFlush.
    586      * <p>
    587      * This stream's error flag is set to {@code true} if it is closed or an I/O
    588      * error occurs.
    589      *
    590      * @param oneByte
    591      *            the byte to be written
    592      */
    593     @Override
    594     public synchronized void write(int oneByte) {
    595         if (out == null) {
    596             setError();
    597             return;
    598         }
    599         try {
    600             out.write(oneByte);
    601             int b = oneByte & 0xFF;
    602             // 0x0A is ASCII newline, 0x15 is EBCDIC newline.
    603             boolean isNewline = b == 0x0A || b == 0x15;
    604             if (autoFlush && isNewline) {
    605                 flush();
    606             }
    607         } catch (IOException e) {
    608             setError();
    609         }
    610     }
    611 
    612     /**
    613      * Appends the char {@code c}.
    614      * @return this stream.
    615      */
    616     public PrintStream append(char c) {
    617         print(c);
    618         return this;
    619     }
    620 
    621     /**
    622      * Appends the CharSequence {@code charSequence}, or {@code "null"}.
    623      * @return this stream.
    624      */
    625     public PrintStream append(CharSequence charSequence) {
    626         if (charSequence == null) {
    627             print("null");
    628         } else {
    629             print(charSequence.toString());
    630         }
    631         return this;
    632     }
    633 
    634     /**
    635      * Appends a subsequence of CharSequence {@code charSequence}, or {@code "null"}.
    636      *
    637      * @param charSequence
    638      *            the character sequence appended to the target stream.
    639      * @param start
    640      *            the index of the first char in the character sequence appended
    641      *            to the target stream.
    642      * @param end
    643      *            the index of the character following the last character of the
    644      *            subsequence appended to the target stream.
    645      * @return this stream.
    646      * @throws IndexOutOfBoundsException
    647      *             if {@code start > end}, {@code start < 0}, {@code end < 0} or
    648      *             either {@code start} or {@code end} are greater or equal than
    649      *             the length of {@code charSequence}.
    650      */
    651     public PrintStream append(CharSequence charSequence, int start, int end) {
    652         if (charSequence == null) {
    653             charSequence = "null";
    654         }
    655         print(charSequence.subSequence(start, end).toString());
    656         return this;
    657     }
    658 }
    659