/*
* 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 java.io;
import java.util.Formatter;
import java.util.IllegalFormatException;
import java.util.Locale;
/**
* Wraps either an existing {@link OutputStream} or an existing {@link Writer}
* and provides convenience methods for printing common data types in a human
* readable format. No {@code IOException} is thrown by this class. Instead,
* callers should use {@link #checkError()} to see if a problem has occurred in
* this writer.
*/
public class PrintWriter extends Writer {
/**
* The writer to print data to.
*/
protected Writer out;
/**
* Indicates whether this PrintWriter is in an error state.
*/
private boolean ioError;
/**
* Indicates whether or not this PrintWriter should flush its contents after
* printing a new line.
*/
private boolean autoFlush;
/**
* Constructs a new {@code PrintWriter} with {@code out} as its target
* stream. By default, the new print writer does not automatically flush its
* contents to the target stream when a newline is encountered.
*
* @param out
* the target output stream.
* @throws NullPointerException
* if {@code out} is {@code null}.
*/
public PrintWriter(OutputStream out) {
this(new OutputStreamWriter(out), false);
}
/**
* Constructs a new {@code PrintWriter} with {@code out} as its target
* stream. The parameter {@code autoFlush} determines if the print writer
* automatically flushes its contents to the target stream when a newline is
* encountered.
*
* @param out
* the target output stream.
* @param autoFlush
* indicates whether contents are flushed upon encountering a
* newline sequence.
* @throws NullPointerException
* if {@code out} is {@code null}.
*/
public PrintWriter(OutputStream out, boolean autoFlush) {
this(new OutputStreamWriter(out), autoFlush);
}
/**
* Constructs a new {@code PrintWriter} with {@code wr} as its target
* writer. By default, the new print writer does not automatically flush its
* contents to the target writer when a newline is encountered.
*
* @param wr
* the target writer.
* @throws NullPointerException
* if {@code wr} is {@code null}.
*/
public PrintWriter(Writer wr) {
this(wr, false);
}
/**
* Constructs a new {@code PrintWriter} with {@code out} as its target
* writer. The parameter {@code autoFlush} determines if the print writer
* automatically flushes its contents to the target writer when a newline is
* encountered.
*
* @param wr
* the target writer.
* @param autoFlush
* indicates whether to flush contents upon encountering a
* newline sequence.
* @throws NullPointerException
* if {@code out} is {@code null}.
*/
public PrintWriter(Writer wr, boolean autoFlush) {
super(wr);
this.autoFlush = autoFlush;
out = wr;
}
/**
* Constructs a new {@code PrintWriter} with {@code file} as its target. The
* VM's default character set is used for character encoding.
* The print writer does not automatically flush its contents to the target
* file when a newline is encountered. The output to the file is buffered.
*
* @param file
* the target file. If the file already exists, its contents are
* removed, otherwise a new file is created.
* @throws FileNotFoundException
* if an error occurs while opening or creating the target file.
*/
public PrintWriter(File file) throws FileNotFoundException {
this(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(file))), false);
}
/**
* Constructs a new {@code PrintWriter} with {@code file} as its target. The
* character set named {@code csn} is used for character encoding.
* The print writer does not automatically flush its contents to the target
* file when a newline is encountered. The output to the file is buffered.
*
* @param file
* the target file. If the file already exists, its contents are
* removed, otherwise a new file is created.
* @param csn
* the name of the character set used for character encoding.
* @throws FileNotFoundException
* if an error occurs while opening or creating the target file.
* @throws NullPointerException
* if {@code csn} is {@code null}.
* @throws UnsupportedEncodingException
* if the encoding specified by {@code csn} is not supported.
*/
public PrintWriter(File file, String csn) throws FileNotFoundException,
UnsupportedEncodingException {
this(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(file)), csn),
false);
}
/**
* Constructs a new {@code PrintWriter} with the file identified by {@code
* fileName} as its target. The VM's default character set is
* used for character encoding. The print writer does not automatically
* flush its contents to the target file when a newline is encountered. The
* output to the file is buffered.
*
* @param fileName
* the target file's name. If the file already exists, its
* contents are removed, otherwise a new file is created.
* @throws FileNotFoundException
* if an error occurs while opening or creating the target file.
*/
public PrintWriter(String fileName) throws FileNotFoundException {
this(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(fileName))),
false);
}
/**
* Constructs a new {@code PrintWriter} with the file identified by {@code
* fileName} as its target. The character set named {@code csn} is used for
* character encoding. The print writer does not automatically flush its
* contents to the target file when a newline is encountered. The output to
* the file is buffered.
*
* @param fileName
* the target file's name. If the file already exists, its
* contents are removed, otherwise a new file is created.
* @param csn
* the name of the character set used for character encoding.
* @throws FileNotFoundException
* if an error occurs while opening or creating the target file.
* @throws NullPointerException
* if {@code csn} is {@code null}.
* @throws UnsupportedEncodingException
* if the encoding specified by {@code csn} is not supported.
*/
public PrintWriter(String fileName, String csn)
throws FileNotFoundException, UnsupportedEncodingException {
this(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(fileName)), csn),
false);
}
/**
* Flushes this writer and returns the value of the error flag.
*
* @return {@code true} if either an {@code IOException} has been thrown
* previously or if {@code setError()} has been called;
* {@code false} otherwise.
* @see #setError()
*/
public boolean checkError() {
Writer delegate = out;
if (delegate == null) {
return ioError;
}
flush();
return ioError || delegate.checkError();
}
/**
* Sets the error state of the stream to false.
* @since 1.6
*/
protected void clearError() {
synchronized (lock) {
ioError = false;
}
}
/**
* Closes this print writer. Flushes this writer and then closes the target.
* If an I/O error occurs, this writer's error flag is set to {@code true}.
*/
@Override
public void close() {
synchronized (lock) {
if (out != null) {
try {
out.close();
} catch (IOException e) {
setError();
}
out = null;
}
}
}
/**
* Ensures that all pending data is sent out to the target. It also
* flushes the target. If an I/O error occurs, this writer's error
* state is set to {@code true}.
*/
@Override
public void flush() {
synchronized (lock) {
if (out != null) {
try {
out.flush();
} catch (IOException e) {
setError();
}
} else {
setError();
}
}
}
/**
* Formats {@code args} according to the format string {@code format}, and writes the result
* to this stream. This method uses the user's default locale.
* See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
* If automatic flushing is enabled then the buffer is flushed as well.
*
* @param format the format string (see {@link java.util.Formatter#format})
* @param args
* the list of arguments passed to the formatter. If there are
* more arguments than required by {@code format},
* additional arguments are ignored.
* @return this writer.
* @throws IllegalFormatException
* if the format string is illegal or incompatible with the
* arguments, if there are not enough arguments or if any other
* error regarding the format string or arguments is detected.
* @throws NullPointerException if {@code format == null}
*/
public PrintWriter format(String format, Object... args) {
return format(Locale.getDefault(), format, args);
}
/**
* Writes a string formatted by an intermediate {@code Formatter} to the
* target using the specified locale, format string and arguments. If
* automatic flushing is enabled then this writer is flushed.
*
* @param l
* the locale used in the method. No localization will be applied
* if {@code l} is {@code null}.
* @param format the format string (see {@link java.util.Formatter#format})
* @param args
* the list of arguments passed to the formatter. If there are
* more arguments than required by {@code format},
* additional arguments are ignored.
* @return this writer.
* @throws IllegalFormatException
* if the format string is illegal or incompatible with the
* arguments, if there are not enough arguments or if any other
* error regarding the format string or arguments is detected.
* @throws NullPointerException if {@code format == null}
*/
public PrintWriter format(Locale l, String format, Object... args) {
if (format == null) {
throw new NullPointerException("format == null");
}
new Formatter(this, l).format(format, args);
if (autoFlush) {
flush();
}
return this;
}
/**
* Prints a formatted string. The behavior of this method is the same as
* this writer's {@code #format(String, Object...)} method.
*
* <p>The {@code Locale} used is the user's default locale.
* See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
*
* @param format the format string (see {@link java.util.Formatter#format})
* @param args
* the list of arguments passed to the formatter. If there are
* more arguments than required by {@code format},
* additional arguments are ignored.
* @return this writer.
* @throws IllegalFormatException
* if the format string is illegal or incompatible with the
* arguments, if there are not enough arguments or if any other
* error regarding the format string or arguments is detected.
* @throws NullPointerException if {@code format == null}
*/
public PrintWriter printf(String format, Object... args) {
return format(format, args);
}
/**
* Prints a formatted string. The behavior of this method is the same as
* this writer's {@code #format(Locale, String, Object...)} method.
*
* @param l
* the locale used in the method. No localization will be applied
* if {@code l} is {@code null}.
* @param format the format string (see {@link java.util.Formatter#format})
* @param args
* the list of arguments passed to the formatter. If there are
* more arguments than required by {@code format},
* additional arguments are ignored.
* @return this writer.
* @throws IllegalFormatException
* if the format string is illegal or incompatible with the
* arguments, if there are not enough arguments or if any other
* error regarding the format string or arguments is detected.
* @throws NullPointerException if {@code format == null}
*/
public PrintWriter printf(Locale l, String format, Object... args) {
return format(l, format, args);
}
/**
* Prints the string representation of the specified character array
* to the target.
*
* @param charArray
* the character array to print to the target.
* @see #print(String)
*/
public void print(char[] charArray) {
print(new String(charArray, 0, charArray.length));
}
/**
* Prints the string representation of the specified character to the
* target.
*
* @param ch
* the character to print to the target.
* @see #print(String)
*/
public void print(char ch) {
print(String.valueOf(ch));
}
/**
* Prints the string representation of the specified double to the target.
*
* @param dnum
* the double value to print to the target.
* @see #print(String)
*/
public void print(double dnum) {
print(String.valueOf(dnum));
}
/**
* Prints the string representation of the specified float to the target.
*
* @param fnum
* the float value to print to the target.
* @see #print(String)
*/
public void print(float fnum) {
print(String.valueOf(fnum));
}
/**
* Prints the string representation of the specified integer to the target.
*
* @param inum
* the integer value to print to the target.
* @see #print(String)
*/
public void print(int inum) {
print(String.valueOf(inum));
}
/**
* Prints the string representation of the specified long to the target.
*
* @param lnum
* the long value to print to the target.
* @see #print(String)
*/
public void print(long lnum) {
print(String.valueOf(lnum));
}
/**
* Prints the string representation of the specified object to the target.
*
* @param obj
* the object to print to the target.
* @see #print(String)
*/
public void print(Object obj) {
print(String.valueOf(obj));
}
/**
* Prints a string to the target. The string is converted to an array of
* bytes using the encoding chosen during the construction of this writer.
* The bytes are then written to the target with {@code write(int)}.
* <p>
* If an I/O error occurs, this writer's error flag is set to {@code true}.
*
* @param str
* the string to print to the target.
* @see #write(int)
*/
public void print(String str) {
write(str != null ? str : String.valueOf((Object) null));
}
/**
* Prints the string representation of the specified boolean to the target.
*
* @param bool
* the boolean value to print the target.
* @see #print(String)
*/
public void print(boolean bool) {
print(String.valueOf(bool));
}
/**
* Prints a newline. Flushes this writer if the autoFlush flag is set to {@code true}.
*/
public void println() {
synchronized (lock) {
print(System.lineSeparator());
if (autoFlush) {
flush();
}
}
}
/**
* Prints the string representation of the character array {@code chars} followed by a newline.
* Flushes this writer if the autoFlush flag is set to {@code true}.
*/
public void println(char[] chars) {
println(new String(chars, 0, chars.length));
}
/**
* Prints the string representation of the char {@code c} followed by a newline.
* Flushes this writer if the autoFlush flag is set to {@code true}.
*/
public void println(char c) {
println(String.valueOf(c));
}
/**
* Prints the string representation of the double {@code d} followed by a newline.
* Flushes this writer if the autoFlush flag is set to {@code true}.
*/
public void println(double d) {
println(String.valueOf(d));
}
/**
* Prints the string representation of the float {@code f} followed by a newline.
* Flushes this writer if the autoFlush flag is set to {@code true}.
*/
public void println(float f) {
println(String.valueOf(f));
}
/**
* Prints the string representation of the int {@code i} followed by a newline.
* Flushes this writer if the autoFlush flag is set to {@code true}.
*/
public void println(int i) {
println(String.valueOf(i));
}
/**
* Prints the string representation of the long {@code l} followed by a newline.
* Flushes this writer if the autoFlush flag is set to {@code true}.
*/
public void println(long l) {
println(String.valueOf(l));
}
/**
* Prints the string representation of the object {@code o}, or {@code "null},
* followed by a newline.
* Flushes this writer if the autoFlush flag is set to {@code true}.
*/
public void println(Object obj) {
println(String.valueOf(obj));
}
/**
* Prints the string representation of the string {@code s} followed by a newline.
* Flushes this writer if the autoFlush flag is set to {@code true}.
*
* <p>The string is converted to an array of bytes using the
* encoding chosen during the construction of this writer. The bytes are
* then written to the target with {@code write(int)}. Finally, this writer
* is flushed if the autoFlush flag is set to {@code true}.
*
* <p>If an I/O error occurs, this writer's error flag is set to {@code true}.
*/
public void println(String str) {
synchronized (lock) {
print(str);
println();
}
}
/**
* Prints the string representation of the boolean {@code b} followed by a newline.
* Flushes this writer if the autoFlush flag is set to {@code true}.
*/
public void println(boolean b) {
println(String.valueOf(b));
}
/**
* Sets the error flag of this writer to true.
*/
protected void setError() {
synchronized (lock) {
ioError = true;
}
}
/**
* Writes the character buffer {@code buf} to the target.
*
* @param buf
* the non-null array containing characters to write.
*/
@Override
public void write(char[] buf) {
write(buf, 0, buf.length);
}
/**
* Writes {@code count} characters from {@code buffer} starting at {@code
* offset} to the target.
* <p>
* This writer's error flag is set to {@code true} if this writer is closed
* or an I/O error occurs.
*
* @param buf
* the buffer to write to the target.
* @param offset
* the index of the first character in {@code buffer} to write.
* @param count
* the number of characters in {@code buffer} to write.
* @throws IndexOutOfBoundsException
* if {@code offset < 0} or {@code count < 0}, or if {@code
* offset + count} is greater than the length of {@code buf}.
*/
@Override
public void write(char[] buf, int offset, int count) {
doWrite(buf, offset, count);
}
/**
* Writes one character to the target. Only the two least significant bytes
* of the integer {@code oneChar} are written.
* <p>
* This writer's error flag is set to {@code true} if this writer is closed
* or an I/O error occurs.
*
* @param oneChar
* the character to write to the target.
*/
@Override
public void write(int oneChar) {
doWrite(new char[] { (char) oneChar }, 0, 1);
}
private final void doWrite(char[] buf, int offset, int count) {
synchronized (lock) {
if (out != null) {
try {
out.write(buf, offset, count);
} catch (IOException e) {
setError();
}
} else {
setError();
}
}
}
/**
* Writes the characters from the specified string to the target.
*
* @param str
* the non-null string containing the characters to write.
*/
@Override
public void write(String str) {
write(str.toCharArray());
}
/**
* Writes {@code count} characters from {@code str} starting at {@code
* offset} to the target.
*
* @param str
* the non-null string containing the characters to write.
* @param offset
* the index of the first character in {@code str} to write.
* @param count
* the number of characters from {@code str} to write.
* @throws IndexOutOfBoundsException
* if {@code offset < 0} or {@code count < 0}, or if {@code
* offset + count} is greater than the length of {@code str}.
*/
@Override
public void write(String str, int offset, int count) {
write(str.substring(offset, offset + count).toCharArray());
}
/**
* Appends the character {@code c} to the target.
*
* @param c
* the character to append to the target.
* @return this writer.
*/
@Override
public PrintWriter append(char c) {
write(c);
return this;
}
/**
* Appends the character sequence {@code csq} to the target. This
* method works the same way as {@code PrintWriter.print(csq.toString())}.
* If {@code csq} is {@code null}, then the string "null" is written
* to the target.
*
* @param csq
* the character sequence appended to the target.
* @return this writer.
*/
@Override
public PrintWriter append(CharSequence csq) {
if (csq == null) {
csq = "null";
}
append(csq, 0, csq.length());
return this;
}
/**
* Appends a subsequence of the character sequence {@code csq} to the
* target. This method works the same way as {@code
* PrintWriter.print(csq.subsequence(start, end).toString())}. If {@code
* csq} is {@code null}, then the specified subsequence of the string "null"
* will be written to the target.
*
* @param csq
* the character sequence appended to the target.
* @param start
* the index of the first char in the character sequence appended
* to the target.
* @param end
* the index of the character following the last character of the
* subsequence appended to the target.
* @return this writer.
* @throws StringIndexOutOfBoundsException
* if {@code start > end}, {@code start < 0}, {@code end < 0} or
* either {@code start} or {@code end} are greater or equal than
* the length of {@code csq}.
*/
@Override
public PrintWriter append(CharSequence csq, int start, int end) {
if (csq == null) {
csq = "null";
}
String output = csq.subSequence(start, end).toString();
write(output, 0, output.length());
return this;
}
}