I've reduced your question to its essence:
public class Test {
static byte[] bytes = new byte[10_000_000];
static {
for (int i = 0; i < bytes.length; i++) bytes[i] = (byte) (i%100+32);
}
public static void main(String[] args) throws Exception {
writer(true);
writer(false);
stream(true);
stream(false);
}
static void writer(boolean flush) throws IOException {
Writer out = new FileWriter("output.txt");
long a = System.currentTimeMillis();
for (byte j : bytes) {
out.write(j);
if (flush) out.flush();
}
out.close();
System.out.println("FileWriter with" + (flush? "":"out") + " flushing: " +
(System.currentTimeMillis() - a));
}
static void stream(boolean flush) throws IOException {
OutputStream out = new FileOutputStream("output.txt");
long a = System.currentTimeMillis();
for (byte j : bytes) {
out.write(j);
if (flush) out.flush();
}
out.close();
System.out.println("FileOutputStream with" + (flush? "":"out") + " flushing: " +
(System.currentTimeMillis() - a));
}
}
Notes:
- properly closing the resources when done;
- double loop replaced by single loop, but a larger array;
- avoid writing control characters to evade autoflush behavior;
- only using byte array since you are testing only one method in all cases:
write(int). Therefore it makes no difference whether you are using bytes or chars; - removed everything except a
FileWriterand aFileOutputStreambecause all other cases boil down to these two; - testing both writer and output stream in two modes: flush after each write, and don't flush at all until close.
Now, when you run this, you'll get output like the following:
FileWriter with flushing: 28235
FileWriter without flushing: 828
FileOutputStream with flushing: 23984
FileOutputStream without flushing: 23641
So, what's the lesson?
- all writers are buffered because internally they delegate to
StreamEncoderwhich is itself buffered; FileOutputStreamis not buffered;- non-buffered writing byte-by-byte is very slow.
Good practices demand that you always do buffered writing: either using buffered sinks, or maintaining an explicit buffer on your side.
Answer from Marko Topolnik on Stack OverflowOutputStream.write(byte[])writes the bytes as binary data.PrintWriter.print(byte[])callstoString()on the array and writes out the result. The[B@19e3118ais thetoString()representation of your array.
Given that the string only contains ASCII characters, you could use String(byte[]) on your array, and print the result.
Alternatively, if you're using the Apache Commons Base64 class, you should simply use the encodeBase64String() method instead of encodeBase64() [Thanks @SimonC].
[B@19e3118a is the result of calling toString() on a byte array. I don't know which Base64 class you're using, but you should find one which encodes byte arrays to Strings, and not byte arrays to other byte arrays, if you want to use a Writer.
I don't see where you are closing the file. I don't see you reading anything either.
I assume you want to append to the file instead of overwriting it each time. In that case you need to use the append option of FileOutputStream as this is not the default behaviour.
PrintStream writetoEngineer = new PrintStream(
new FileOutputStream("Engineer.txt", true));
BTW: e.toString() + " " is almost the same as e + " " except the latter doesn't throw an exception if e is null.
Since the code given code snippet isn't a Self Contained Compilable Example (it is Simple though), I can just guess that the PrintStream is created inside the loop, per each iteration over the Engineer collection. That would cause the file to be truncated as indicate in PrintStream's constructor javadoc:
Parameters:
file - The file to use as the destination of this print stream. If the file exists, then it will be truncated to zero size; otherwise, a new file will be created. The output will be written to the file and is buffered.
try this example code:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
public class PrintEngineers {
public static class Engineer {
private final String firstName;
private final String surName;
private final int weeklySal;
public Engineer(String firstName, String surName, int weeklySal) {
super();
this.firstName = firstName;
this.surName = surName;
this.weeklySal = weeklySal;
}
public int calculateMonthly() {
return weeklySal * 4; // approximately
}
@Override
public String toString() {
return firstName + " " + surName;
}
}
/**
* @param args
* @throws FileNotFoundException
*/
public static void main(String[] args) throws FileNotFoundException {
Engineer e1 = new Engineer("first1", "sur1", 100);
Engineer e2 = new Engineer("first2", "sur2", 200);
Engineer e3 = new Engineer("first3", "sur3", 300);
List<Engineer> engineers = new ArrayList<>(3);
engineers.add(e1);
engineers.add(e2);
engineers.add(e3);
// instanciate PrintStream here, before the loop starts
PrintStream writetoEngineer = new PrintStream(new File("Engineer.txt"));
for (Engineer engineer : engineers) {
// new PrintStream(...) here truncates the file (see javadoc) //This is not append.Only print.Refresh file on each item
writetoEngineer.append(engineer.toString()).append(' ')
.append("" + engineer.calculateMonthly()).append('\n');
}
}
}
OutputStreams are meant for binary data. Writers (including PrintWriter) are meant for text data.
You may not see the difference in your specific situation as you're calling PrintWriter.write(int) which writes a single character - if the character encoding you're using just maps characters to the same byte, for characters less than 127, then you'll see the same result. But if you give it a different encoding, then you'll see a difference.
PrintWriter is also different in that it suppresses IO exceptions - as does PrintStream, which is the binary stream equivalent of PrintWriter.
From this java2novice.com link I extracted the following, that is similar to what Jon said:
ServletOutputStream: ServletResponse.getOutputStream() returns a ServletOutputStream
suitable for writing binary data in the response. The servlet
container does not encode the binary data, it sends the raw data
as it is.
PrintWriter: ServletResponse.getWriter() returns PrintWriter object which sends
character text to the client. The PrintWriter uses the character
encoding returned by getCharacterEncoding(). If the response's
character encoding has not been specified then it does default
character encoding.
According to coderanch.com, if we combine the answers we get:
FileWriter is the character representation of IO. That means it can be used to write characters. Internally FileWriter would use the default character set of the underlying OS and convert the characters to bytes and write it to the disk.
PrintWriter & FileWriter.
Similarities
- Both extend from Writer.
- Both are character representation classes, that means they work with characters and convert them to bytes using default charset.
Differences
- FileWriter throws IOException in case of any IO failure, this is a checked exception.
- None of the PrintWriter methods throw IOExceptions, instead they set a boolean flag which can be obtained using checkError().
- PrintWriter has an optional constructor you may use to enable auto-flushing when specific methods are called. No such option exists in FileWriter.
- When writing to files, FileWriter has an optional constructor which allows it to append to the existing file when the "write()" method is called.
Difference between PrintStream and OutputStream: Similar to the explanation above, just replace character with byte.
PrintWriter has following methods :
close()
flush()
format()
printf()
print()
println()
write()
and constructors are :
File (as of Java 5)
String (as of Java 5)
OutputStream
Writer
while FileWriter having following methods :
close()
flush()
write()
and constructors are :
File
String
Link: http://www.coderanch.com/t/418148/java-programmer-SCJP/certification/Information-PrintWriter-FileWriter
Both of these use a FileOutputStream internally:
public PrintWriter(File file) throws FileNotFoundException {
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
false);
}
public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
}
but the main difference is that PrintWriter offers special methods:
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.
Unlike the PrintStream class, if automatic flushing is enabled it will be done only when one of the println, printf, or format methods is invoked, rather than whenever a newline character happens to be output. These methods use the platform's own notion of line separator rather than the newline character.
From java docs
A DataOutputStream lets an application write primitive Java data types to an output stream in a portable way. An application can then use a data input stream to read the data back in.
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.
In one sentence the difference is:
OutputStreams are meant for binary data. Writers (including PrintWriter) are meant for text data
PrintWriter converts everything to Ascii format. For example:
PrintWriter pw = new PrintWriter(new File("./test.txt"));
for (Integer word: words) {
pw.println(word);
}
in this block of code, by calling pw.printin(word); no matter what the type of word is (which is integer here), program converts it to ASCII format and stores it. As a result, when we want to retrieve that stored data and read it again, program have to do another type changing from text to original format! -which is not good in term of time efficiency!
For instance, if that word is an integer, after storing that into a file (which is text now), program has to change its format from String to integer when it is going to retrieve that!
But, DataOutPutStream makes everything much easier since it stores the data into bytes by keeping data type. So, when we run bellow block, program stored integer as byte and when it want to retrieve that it does not need any change of type. It's stored as integer and retrieved as integer too. So, it is much faster!
DataOutputStream dos = new DataOutputStream(
new FileOutputStream(new File("test2.txt")));
for (Integer word: words) {
dos.writeUTF(word);
}
dos.close();
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.
Files contain bytes. Always.
Characters are written into files by transforming characters into bytes, using an encoding. Many such encodings exist. For example, ASCII allows transforming 128 different characters to bytes. UTF-8 allows encoding any Unicode character to bytes. The two encodings, for example, transform the character '1' into the byte 49. '2' would be transformed into the byte 50.
When using a PrintWriter with a file name as argument, the PrintWriter actually opens a FileOuptutStream to write bytes to the file. When you write characters to the PrintWriter, the PrintWriter transforms characters to bytes using an encoding, and then write those bytes to the FileOutputStream, which writes the bytes to the file.
So, for example, if you use the following program:
public class Main {
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream(new File("data")) ;
for(int i = 49; i <= 58; ++i)
fos.write(i);
fos.close();
}
}
and then open the file with a text editor, you should see 123456789 in the file, because the code writes the byte representation (in ASCII or UTF8) of those characters directly.
Look at the docs.
From FileOutputStream.html#write(int):
Writes the specified byte to this file output stream.
From PrintWriter.html#print(int):
Prints an integer. The string produced by
String.valueOf(int)is translated into bytes according to the platform's default character encoding, and these bytes are written in exactly the manner of the write(int) method.
That is, this method will write numbers as you see them. The other one writes bytes. The byte value 9 is not the number 9, but an unreadable character.
This might sound flippant, but PrintStream prints to an OutputStream, and PrintWriter prints to a Writer. Ok, I doubt I'll get any points for stating the obvious. But there's more.
So, what is the difference between an OutputStream and a Writer?
Both are streams, with the primary difference being a OutputStream is a stream of bytes while a Writer is a stream of characters.
If an OutputStream deals with bytes, what about PrintStream.print(String)? It converts chars to bytes using the default platform encoding. Using the default encoding is generally a bad thing since it can lead to bugs when moving from one platform to another, especially if you are generating the file on one platform and consuming it on another.
With a Writer, you typically specify the encoding to use, avoiding any platform dependencies.
Why bother having a PrintStream in the JDK, since the primary intent is to write characters, and not bytes? PrintStream predates JDK 1.1 when Reader/Writer character streams were introduced. I imagine Sun would have deprecated PrintStream if only for the fact it is so widely used. (After all, you wouldn't want each call to System.out to generate a deprecated API warning! Also, changing the type from PrintStream to PrintWriter on the standard output streams would have broken existing applications.)
Since JDK 1.4 it's possible to specify the character encoding for a PrintStream. Thus, the differences between PrintStream and PrintWriter are only about auto flushing behavior and that a PrintStream cannot wrap a Writer.
No, you only need to close the outermost stream. It will delegate all the way to the wrapped streams.
However, your code contains one conceptual failure, the close should happen in finally, otherwise it's never closed when the code throws an exception between opening and closing.
E.g.
public static void main(String args[]) throws IOException {
PrintStream ps = null;
try {
ps = new PrintStream(new FileOutputStream("myfile.txt"));
ps.println("This data is written to a file:");
System.out.println("Write successfully");
} catch (IOException e) {
System.err.println("Error in writing to file");
throw e;
} finally {
if (ps != null) ps.close();
}
}
(note that I changed the code to throw the exception so that you understand the reason of the problem, the exception namely contains detailed information about the cause of the problem)
Or, when you're already on Java 7, then you can also make use of ARM (Automatic Resource Management; also known as try-with-resources) so that you don't need to close anything yourself:
public static void main(String args[]) throws IOException {
try (PrintStream ps = new PrintStream(new FileOutputStream("myfile.txt"))) {
ps.println("This data is written to a file:");
System.out.println("Write successfully");
} catch (IOException e) {
System.err.println("Error in writing to file");
throw e;
}
}
No , here is implementation of PrintStream's close() method:
public void close() {
synchronized (this) {
if (! closing) {
closing = true;
try {
textOut.close();
out.close();
}
catch (IOException x) {
trouble = true;
}
textOut = null;
charOut = null;
out = null;
}
}
You can see out.close(); which closes output stream.