PrintStream vs PrintWriter - java

I have searched the site and have found some answers, but i'm having trouble understanding the difference between these two classes. Can someone explain the differences between these two classes?

PrintStream was the original bridge to deal with encoding characters and other datatypes. If you look at the javadoc for java.io.OutputStream you'll see methods only for writing two distinct data types: byte and int.
In early versions of the JDK (1.0.x), when you wanted to write characters, you could do one of two things, write bytes to an output stream (which are assumed to be in the system default character set):
outputStream.write("foobar".getBytes());
or wrap another outputStream in a PrintStream:
PrintStream printStream = new PrintStream(outputStream);
printStream.write("foobar");
See the difference? PrintStream is handling the character conversion to bytes, as well as encoding (the constructor call above uses the system default encoding, but you could pass it as a parameter). It also provides convenience methods for writing double, boolean, etc....
In fact System.out and System.err are defined as PrintStream instances.
Along comes JDK 1.1, and they realize they need a better way to deal with pure character data, since PrintStream still has the byte based methods for writing. So they introduced the Writer abstract class to deal strictly with char, String and int data.
PrintWriter adds methods for other types like double, boolean, etc...
Nowadays PrintWriter also has format() / printf() methods for format printing, etc...
As a general rule, if you're writing character data, use Writer instances. If you're writing binary (or mixed) data use OutputStream instances.

From the Javadoc for PrintWriter:
Prints formatted representations of objects to a text-output stream. This class implements all of the print methods found in PrintStream. It does not contain methods for writing raw bytes, for which a program should use unencoded byte streams.
Think of it this way: a PrintStream sits on top of some OutputStream. Since output streams deal with bytes rather than characters, the PrintStream must take responsibility for encoding characters into bytes. The OutputStream 'merely' writes the bytes out to a file/console/socket whatever.
A PrintWriter, on the other hand, sits on top of a Writer. Since the Writer is responsible for encoding characters into bytes, the PrintWriter does not do encoding. I just knows about newlines etc. (Yes, PrintWriters do have constructors that take Files and OutputStreams, but those are simply conveniences. For example, PrintWriter(OutputStream).
Creates a new PrintWriter, without automatic line flushing, from an existing OutputStream. This convenience constructor creates the necessary intermediate OutputStreamWriter, which will convert characters into bytes using the default character encoding.
BTW, In case you are thinking that the PrintWriter really doesn't have much utility, remember that both PrintWriter and PrintStream absorb IOExceptions from printing logic.

To add Matt's answer:
I compared PrintStream and PrintWriter,
the most useful part, the constructor ClassName(String fileName, String charsetName) and the print(), println(), printf()/format() functions are supported by both classes.
The differences are:
Since JDK1.0 vs JDK1.1
Constructors:
PrintStream(OutputStream out, boolean autoFlush, String charsetName)
PrintWriter(Writer wr)
PrintWriter(Writer wr, boolean autoFlush)
Methods inherited from FilterOutputStream/OutputStream vs Writer, the difference boils down to byte vs char:
PrintStream.write(byte[] buffer, int offset, int count)
PrintStream.write(byte[] buffer)
PrintStream.write(int oneByte)
PrintWriter.write(int oneChar)
PrintWriter.write(char[] buf)
PrintWriter.write(char[] buf, int offset, int count)
PrintWriter.write(String str)
PrintWriter.write(String str, int offset, int count)
PrintStream.printf() corresponds to PrintWriter.format()
It indeed looks like in 1.1. they thought out a better class, but could not remove the old 1.0 class without breaking existing programs.

Related

How do I choose which of the main Java IO classes I need to write strings to a file?

There are many different classes in the IO package, some seems to only have suble differences.
If you are to write some Strings to a text file, and read them for later use.
Which classes would you use for each of those two purposes and why?
BufferedInputStream
BufferedOutputStream
BufferedWriter
BufferedReader
DataInputStream
DataOutputStream
FileInputStream
FileOutputStream
FileReader
FileWriter
InputStreamReader
OutputStreamReader
Reader
Writer
It all depends on what you want to do.
Output Streams
In case you want to write byte data, you would use some subclass of OutputStream that is used to write bytes in destination defined by concrete subclass.
For example FileOutputStream is used to write data in file byte by byte (or bunch of bytes).
BufferedOutputStream is an optimized extension of FileOutputStream to write blocks of bytes to minimize number of disk operations. So when you call write, actually it may or may not be written in file - depends on buffer's state whether it is full or not. If buffer reaches it's max capacity, all bytes are flushed to file at once.
ByteArrayOutputStream is using just block of memory as a destination instead of file. Current stream content is obtained via toByteArray() method (why would you need such a stream will be explained later).
ObjectOutputStream is used to write objects (class instances) in some destination defined by the underlying OutputStream. For example, ObjectOutputStream(FileOutputStream) would write an objects in file, while ObjectOutputStream(ByteArrayOutputStream) would write an objects in memory. The last option allows you to serialize objects in byte buffer (array of bytes) which can be then send somewhere via network.
Note, that any object you want to write somewhere via ObjectOutputStream has to implement Serializable interface. Since object may contain references to another objects, all the objects that are accessible from the object to be serialized also has to implement Serializable interface as serialization, by default, is process of writting of full graph of objects - assuming you are not using transient keyword to exclude class field from serialization, or you are not defining at object's class a special methods writeObject/readObject that overrides default serialization behaviour. These methods are designed to implement custom serialization i. e. you can define on your own how to write/read class field in/from ObjectOutputStream/ObjectInputStream. Suppose class A for which you are implementing custom serialization contains an object of class B. Instead of writting object b as a full graph, i. e. instead of calling oos.writeObject(b), where oos is an argument of the writeObject method being implemented in class A, you would write in stream only some fields of class B e. g. oos.writeBoolean(b.isEnabled), oos.writeInt(b.value). As long as object b is not written via oos.writeObject(b), it does not have to implement Serializable interface. For more details see Serializable documentation.
DataOutputStream is used to write primitives like boolean, char, int, long, float, double. Since any object can be decomposed to primitives e. g. class A { int i = 0; B b = new B();}, class B {double d = 0.0;} can be written simply as int a, double d, you can use DataOutputStream to serialize objects in compressed way unlike serialization which writes much more data e. g. class path, class version, ... so ClassLoader can identify a given class in runtime, instantiate this class and finally load data to this empty object. Note that instantiating class by it's name + initialising object in this way is much slower than instantiating class on your own and initializing it's fields on your own from "raw" DataOutputStream (that's why OS Android prefers custom Parcelable interface over standard serialization, which works as writting/reading to/from DataOutputStream/DataInputStream).
In case you want to write string data, you would use OutputStreamWriter a higher level of output-stream which writes characters/Strings in destination defined by OutputStream (in case of writting in file, you would pass FileOutputStream, in case of writtin in memory you would pass ByteArrayOutputStream).
FileWriter is an extension of OutputStreamWriter designed for writting in file.
BufferedWriter works the same as BufferedOutputStream except it is designed for work with strings and characters.
CharArrayWriter works the same as ByteArrayOutputStream except characters are stored in char[] which is obtained by calling getCharArray().
StringWriter is similar to CharArrayWriter except it allows you to write strings which are stored in StringBuffer that is obtained by calling getBuffer().
PrintWriter allows you to write formatted strings in specified destination defined by OutputStream (this writer is designed for easy logging).
Input Streams
The same concept is applied to input-streams (readers) associated with given output-streams (writers) mentioned above.
Readers and InputStreams are for input while Writers and OutputStreams are for output.
Readers and Writers are for text (with a character set) while InputStreams and OutputStreams are for binary data (such as images).
Buffering helps with performance because reads and writes are batched rather than making a system call each time any method is used.
If it has "File" in the name, it is used for files.
So for your specific case you want to write text to a file, the most obvious candidate is a FileWriter:
Writer out = new FileWriter(
new File("foo.txt")
);
If you want better performance for making many small writes to it, you could wrap it in a buffer:
Writer out = new BufferedWriter(
new FileWriter(
new File("foo.txt")
)
);
The FileWriter assumes the default character encoding when writing text. If you want to choose the encoding, or ensure that it is consistent on all platforms, you could create the writer from an OutputStream specifying the encoding explicitly:
Writer out = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(
new File("foo.txt")
), "UTF-8"
)
);

Java writing to File or System.out

I need to write characters to a file or to standard output. And I am curious if it could be done with one method.
Now I have something like this:
OutputStream out;
if(toConsole)
out = System.out;
else
out = new FileOutputStream(file);
write(out);
}
void write (OutputStream str){
....
str.write(string);
But it is a problem that I am using (in case when "str" is System.out) write instead print?
(print java doc: "string's characters are converted into bytes according to the platform's default character encoding")
In case if I would use PrintWriter(or PrintStream) as a parameter then i cannot use BufferedWriter and writing to the file would be slower.
It is possible to use a same code (and same methods) for writing to a file and to System.out?
(This is for my school project so I want it to be a "pure" and fully correct)
What you're trying to accomplish, is to treat the fileoutput and the consoleoutput the same. This is possible, because System.out is a PrintStream, and you can create a PrintStream for a file like this
new PrintStream(yourFile)
or insert a BufferedOutputStream in between
new PrintStream(new BufferedOutputStream(new FileOutputStream(yourFile))).
Note that this is not needed, because PrintStream does buffer its output itself.
I would create a variable (global or not), representing the current output.
This might be a PrintStream, either System.out, or a PrintStream around a FileOutputStream, whatever you desire. You would then pass this stream to the write method or call the print methods on it directly.
The advantage is that you can easily switch this without much code modification, you can redirect it wherever you wan't. It's no problem to redirect it to a file and System.out! You wouldn't get that pure flexibility with the way you're writing the method currently.
You could (not saying you should), also redirect System.out directly, using System.setOut. This however is bad style, because it is quite uncommon and might confuse everyone else, if they have not seen the call to System.setOut.
System.out is an object of type PrintStream. So yes, you can write to
System.out and/or to another file using exactly the same methods. Just
construct a PrintStream object and direct it to your file. So declare
your out variable as PrintStream to start with.
See also:
http://docs.oracle.com/javase/7/docs/api/java/lang/System.html
http://docs.oracle.com/javase/7/docs/api/java/io/PrintStream.html

Why need PrintWriter?

I am really confused about the purpose of various io classes, for example, If we have BufferedWriter, why we need a PrintWriter?
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = null;
while(s=br.readline()!=null) {
PrintWriter fs = new PrintWriter(new FileWriter(file));
fs.println(s);
}
if the BufferedWriter can not help? I just do not understand the difference between these io classes, can someone explain me?
They have nothing to do with each other. In all truth, I rarely use PrintWriter except to convert System.out temporarily. But anyway.
BufferedWriter, like BufferedReader/BufferedInputStream/BufferedOutputStream merely decorates the enclosed Writer with a memory buffer (you can specify the size) or accept a default. This is very useful when writing to slow Writers like network or file based. (Stuff is committed in memory and only occasionally to disk for example) By buffering in memory the speed is greatly increased - try writing code that writes to say a 10 mb file with just FileWriter and then compare to the same with BufferedWriter wrapped around it.
So that's BufferedWriter. It throws in a few convenience methods, but mostly it just provides this memory buffer.
PrintWriter mostly is a simple decorator that adds some specific write methods for various types like String, float, etc, so you don't have to convert everything to raw bytes.
Edited:
This already has come up
The PrintWriter is essentially a convenience class. If you want to quickly and easily blast out a line of text to e.g. a log file, PrintWriter makes it very easy.
Three features:
The print and println methods will take any data type and do the conversion for you. Not just String.
The relatively new format method is worth its weight in gold. Now it's as simple in Java as in C to output a line of text with C-style format control.
The methods never throw an exception! Some programmers are horrified at the possibility of never hearing about things going wrong. But if it's a throwaway program or doing something really simple, the convenience can be nice. Especially if output is to System.out or System.err which have few ways of going wrong.
The main reason to use the PrintWriter is to get access to the printXXX methods (like println(int)). You can essentially use a PrintWriter to write to a file just like you would use System.out to write to the console.
A BufferedWriter is an efficient way to write to a file (or anything else) as it will buffer the characters in Java memory before writing to the file.

PrintWriter autoflush puzzling logic

public PrintWriter(OutputStream out, boolean autoFlush):
out - An output stream
autoFlush - A boolean; if true, the println, printf, or format methods
will flush the output buffer
public PrintStream(OutputStream out, boolean autoFlush):
out - The output stream to which values and objects will be printed
autoFlush - A boolean; if true, the output buffer will be flushed
whenever a byte array is written, one of the println methods is invoked,
or a newline character or byte ('\n') is written
What was the reason for changing autoflush logic between these classes?
Because they are always considered as identical except for encoding moments and "autoflush" without flushing on print() hardly corresponds to principle of least astonishment, silly bugs occur:
I created a PrintWriter with autoflush on; why isn't it autoflushing?
I think the answer lies in the history of Java. The trio InputStream, OutputStream and PrintStream in java.io date back to Java 1.0. That is before serious support for file encodings and character sets were built into the language.
To quote the Javadoc:
"A PrintStream adds functionality to
another output stream, namely the
ability to print representations of
various data values conveniently. Two
other features are provided as well.
Unlike other output streams, a
PrintStream never throws an
IOException; instead, exceptional
situations merely set an internal flag
that can be tested via the checkError
method..."
To summarize, it is a convenience for generating textual output, grafted on top of lower level IO.
In Java 1.1, Reader, Writer and PrintWriter were introduced. Those all support character sets. While InputStream and OutputStream still had a real uses (raw data processing), PrintStream became far less relevant, because printing by nature is about text.
The Javadoc for PrintWriter explicitly states:
Unlike the PrintStream class, if
automatic flushing is enabled it will
be done only when one of the println()
methods is invoked, rather than
whenever a newline character happens
to be output. The println() methods
use the platform's own notion of line
separator rather than the newline
character.
Put another way, PrintWriter should only be used through the print*(...) APIs, because writing newline characters etc should not be the caller's responsibility, the same way dealing with file encodings and character sets are not the caller's responsibility.
I would argue that PrintWriter should have been java.io.Printer instead, and not have extended Writer. I don't know whether they extended to mimic PrintStream, or because they were stuck on maintaining the pipe design idiom.
The reason it wasn't the same at start was probably just an accident. Now it's backwards compatibility.

Java's [Input|Output]Streams' one-method-call-for-each-byte: a performance problem?

[Input|Output]Streams exist since JDK1.0, while their character-counterparts Readers|Writers exist since JDK1.1.
Most concepts seem similar, with one exception: the base classes of streams declare an abstract method which processes one single byte at a time, while base readers/writers classes declare an abstract method which processes whole char-arrays.
Thus, given that I understand it correctly, every overridden stream class is limited to process single bytes (thereby performing at least one method call for each byte!), while overridden readers/writers only need a method call per array(-buffer).
Isn't that a huge performance problem?
Can a stream be implemented as subclass of either InputStream or OutputStream, but nevertheless be based on byte-arrays?
Actually, subclasses of InputStream have to override the method that reads a single byte at a time, but also can override others methods that read while byte-arrays. I think that's actually the case for most of the Input/Output streams.
So this isn't much of a performance problem, in my opinion, and yes, you can extend Input/Output stream and be based on byte-arrays.
Single byte reading is almost always a huge performance problem. But if you read the API docs of InputStream, you see that you HAVE TO override read(), but SHOULD also override read(byte[],int,int). Most code that uses any kind of InputStream calls the array style method anyway, but the default implementation of that function is just implemented by calling read() for every byte, so the negative performance impact.
For OutputStream the same holds.
As Daniel said, you must override read(), since client might use it directly, but you also should override read (byte[],int,int).
However, I doubt if you should be concerned with performance since the jvm can and will inline that method for you. Most of all, it doesn't seem like an issue to me.
Also, most readers use some underlying input stream behind the scene, so in any case those char-array based methods end up calling read(byte[],int,int) or even read() directly.
Note that Readers/Writers are for reading characters which can be made of more than one byte such as unicode characters. Streams on the other hand are more suitable when you're dealing with non-string (binary) data.
Apart from that, InputStream and OutputStream also have methods to read/write an entire array of bytes.
performance wise, if you wrap it with BufferedInputStream, JVM should be able to optimize the overhead of single byte read method calls to nothing, i.e. it's as fast as if you do the buffering yourself.

Categories

Resources